]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
New map generator added (and SQLite, messed up the commits at that time...) (import...
[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 void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
2173 {
2174         MapNode stonenode(CONTENT_STONE);
2175
2176         s16 size = myrand_range(8, 16);
2177         
2178         VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
2179         Buffer<u8> stone_d(stone_a.getVolume());
2180         for(s32 i=0; i<stone_a.getVolume(); i++)
2181                 stone_d[i] = 0;
2182
2183         // Force stone at bottom to make it usually touch the ground
2184         {
2185                 for(s16 z=0; z<=0; z++)
2186                 for(s16 y=0; y<=0; y++)
2187                 for(s16 x=0; x<=0; x++)
2188                 {
2189                         stone_d[stone_a.index(v3s16(x,y,z))] = 1;
2190                 }
2191         }
2192
2193         // Generate from perlin noise
2194         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
2195         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
2196         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
2197         {
2198                 double d = 1.0;
2199                 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
2200                                 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
2201                 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
2202                 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
2203                 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
2204                 double dz = (double)z-mid_z;
2205                 double dx = (double)x-mid_x;
2206                 double dy = MYMAX(0, (double)y-mid_y);
2207                 double r = sqrt(dz*dz+dx*dx+dy*dy);
2208                 d /= (2*r/size)*2 + 0.01;
2209                 if(d > 1.0)
2210                 {
2211                         u32 vi = stone_a.index(v3s16(x,y,z));
2212                         stone_d[vi] = 1;
2213                 }
2214         }
2215
2216         /*// Add stone randomly
2217         for(u32 iii=0; iii<7; iii++)
2218         {
2219                 s16 d = 1;
2220
2221                 v3s16 p(
2222                         myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
2223                         myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
2224                         myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
2225                 );
2226
2227                 for(s16 z=0; z<=d; z++)
2228                 for(s16 y=0; y<=d; y++)
2229                 for(s16 x=0; x<=d; x++)
2230                 {
2231                         stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
2232                 }
2233         }*/
2234
2235         // Blit stone to vmanip
2236         for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
2237         for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
2238         for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
2239         {
2240                 v3s16 p(x,y,z);
2241                 p += p0;
2242                 if(vmanip.m_area.contains(p) == false)
2243                         continue;
2244                 u32 vi = vmanip.m_area.index(p);
2245                 /*if(vmanip.m_data[vi].d != CONTENT_AIR
2246                                 && vmanip.m_data[vi].d != CONTENT_IGNORE)
2247                         continue;*/
2248                 u32 i = stone_a.index(x,y,z);
2249                 if(stone_d[i] == 1)
2250                         vmanip.m_data[vi] = stonenode;
2251         }
2252 }
2253
2254 /*
2255         Dungeon making routines
2256 */
2257
2258 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
2259 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
2260 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
2261                 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
2262
2263 void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace)
2264 {
2265         // Make +-X walls
2266         for(s16 z=0; z<roomsize.Z; z++)
2267         for(s16 y=0; y<roomsize.Y; y++)
2268         {
2269                 {
2270                         v3s16 p = roomplace + v3s16(0,y,z);
2271                         if(vmanip.m_area.contains(p) == false)
2272                                 continue;
2273                         u32 vi = vmanip.m_area.index(p);
2274                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2275                                 continue;
2276                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2277                 }
2278                 {
2279                         v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
2280                         if(vmanip.m_area.contains(p) == false)
2281                                 continue;
2282                         u32 vi = vmanip.m_area.index(p);
2283                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2284                                 continue;
2285                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2286                 }
2287         }
2288         
2289         // Make +-Z walls
2290         for(s16 x=0; x<roomsize.X; x++)
2291         for(s16 y=0; y<roomsize.Y; y++)
2292         {
2293                 {
2294                         v3s16 p = roomplace + v3s16(x,y,0);
2295                         if(vmanip.m_area.contains(p) == false)
2296                                 continue;
2297                         u32 vi = vmanip.m_area.index(p);
2298                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2299                                 continue;
2300                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2301                 }
2302                 {
2303                         v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
2304                         if(vmanip.m_area.contains(p) == false)
2305                                 continue;
2306                         u32 vi = vmanip.m_area.index(p);
2307                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2308                                 continue;
2309                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2310                 }
2311         }
2312         
2313         // Make +-Y walls (floor and ceiling)
2314         for(s16 z=0; z<roomsize.Z; z++)
2315         for(s16 x=0; x<roomsize.X; x++)
2316         {
2317                 {
2318                         v3s16 p = roomplace + v3s16(x,0,z);
2319                         if(vmanip.m_area.contains(p) == false)
2320                                 continue;
2321                         u32 vi = vmanip.m_area.index(p);
2322                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2323                                 continue;
2324                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2325                 }
2326                 {
2327                         v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
2328                         if(vmanip.m_area.contains(p) == false)
2329                                 continue;
2330                         u32 vi = vmanip.m_area.index(p);
2331                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
2332                                 continue;
2333                         vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
2334                 }
2335         }
2336         
2337         // Fill with air
2338         for(s16 z=1; z<roomsize.Z-1; z++)
2339         for(s16 y=1; y<roomsize.Y-1; y++)
2340         for(s16 x=1; x<roomsize.X-1; x++)
2341         {
2342                 v3s16 p = roomplace + v3s16(x,y,z);
2343                 if(vmanip.m_area.contains(p) == false)
2344                         continue;
2345                 u32 vi = vmanip.m_area.index(p);
2346                 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
2347                 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
2348         }
2349 }
2350
2351 void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
2352                 u8 avoid_flags, MapNode n, u8 or_flags)
2353 {
2354         for(s16 z=0; z<size.Z; z++)
2355         for(s16 y=0; y<size.Y; y++)
2356         for(s16 x=0; x<size.X; x++)
2357         {
2358                 v3s16 p = place + v3s16(x,y,z);
2359                 if(vmanip.m_area.contains(p) == false)
2360                         continue;
2361                 u32 vi = vmanip.m_area.index(p);
2362                 if(vmanip.m_flags[vi] & avoid_flags)
2363                         continue;
2364                 vmanip.m_flags[vi] |= or_flags;
2365                 vmanip.m_data[vi] = n;
2366         }
2367 }
2368
2369 void make_hole1(VoxelManipulator &vmanip, v3s16 place)
2370 {
2371         make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
2372                         VMANIP_FLAG_DUNGEON_INSIDE);
2373 }
2374
2375 void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir)
2376 {
2377         make_hole1(vmanip, doorplace);
2378 }
2379
2380 v3s16 rand_ortho_dir()
2381 {
2382         if(myrand()%2==0)
2383                 return myrand()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
2384         else
2385                 return myrand()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
2386 }
2387
2388 void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
2389                 v3s16 &result_place, v3s16 &result_dir)
2390 {
2391         make_hole1(vmanip, doorplace);
2392         v3s16 p0 = doorplace;
2393         v3s16 dir = doordir;
2394         u32 length;
2395         if(myrand()%2)
2396                 length = myrand_range(1,13);
2397         else
2398                 length = myrand_range(1,6);
2399         u32 partlength = myrand_range(1,length);
2400         u32 partcount = 0;
2401         s16 make_stairs = 0;
2402         if(myrand()%2 == 0 && partlength >= 3)
2403                 make_stairs = myrand()%2 ? 1 : -1;
2404         for(u32 i=0; i<length; i++)
2405         {
2406                 v3s16 dir0 = dir;
2407                 // If first part of stairs, don't go up or down yet (wouldn't fit)
2408                 if(partcount == 0)
2409                         dir0.Y = 0;
2410                 v3s16 p = p0 + dir0;
2411                 /*// If already empty
2412                 if(vmanip.getNodeNoExNoEmerge(p).d
2413                                 == CONTENT_AIR
2414                 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
2415                                 == CONTENT_AIR)
2416                 {
2417                 }*/
2418                 if(make_stairs)
2419                 {
2420                         make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
2421                                         VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
2422                         make_fill(vmanip, p, v3s16(1,3,1), 0, MapNode(CONTENT_AIR),
2423                                         VMANIP_FLAG_DUNGEON_INSIDE);
2424                 }
2425                 else
2426                 {
2427                         make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
2428                                         VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
2429                         make_hole1(vmanip, p);
2430                         /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
2431                                         VMANIP_FLAG_DUNGEON_INSIDE);*/
2432                 }
2433                 p0 = p;
2434                 partcount++;
2435                 if(partcount >= partlength)
2436                 {
2437                         partcount = 0;
2438                         
2439                         v3s16 newdir = rand_ortho_dir();
2440                         partlength = myrand_range(1,7);
2441                         make_stairs = 0;
2442                         if(myrand()%2 == 0 && partlength >= 3)
2443                                 make_stairs = myrand()%2 ? 1 : -1;
2444
2445                         if(make_stairs != 0)
2446                         {
2447                                 if(newdir.X == 0 && dir.X != 0)
2448                                         dir = newdir;
2449                                 if(newdir.Z == 0 && dir.Z != 0)
2450                                         dir = newdir;
2451                         }
2452                         else
2453                         {
2454                                 dir = newdir;
2455                         }
2456                         dir.Y = make_stairs;
2457                 }
2458         }
2459         //p0.Y -= make_stairs;
2460         dir.Y = 0;
2461         result_place = p0;
2462         result_dir = dir;
2463 }
2464
2465 class RoomWalker
2466 {
2467 public:
2468
2469         RoomWalker(VoxelManipulator &vmanip_, v3s16 pos):
2470                         vmanip(vmanip_),
2471                         m_pos(pos)
2472         {
2473                 randomizeDir();
2474         }
2475
2476         void randomizeDir()
2477         {
2478                 m_dir = rand_ortho_dir();
2479         }
2480
2481         void setPos(v3s16 pos)
2482         {
2483                 m_pos = pos;
2484         }
2485
2486         void setDir(v3s16 dir)
2487         {
2488                 m_dir = dir;
2489         }
2490         
2491         bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
2492         {
2493                 for(u32 i=0; i<100; i++)
2494                 {
2495                         v3s16 p = m_pos + m_dir;
2496                         v3s16 p1 = p + v3s16(0,1,0);
2497                         if(vmanip.m_area.contains(p) == false
2498                                         || vmanip.m_area.contains(p1) == false
2499                                         || i % 4 == 0)
2500                         {
2501                                 randomizeDir();
2502                                 continue;
2503                         }
2504                         if(vmanip.getNodeNoExNoEmerge(p).d
2505                                         == CONTENT_COBBLE
2506                         && vmanip.getNodeNoExNoEmerge(p1).d
2507                                         == CONTENT_COBBLE)
2508                         {
2509                                 // Found wall, this is a good place!
2510                                 result_place = p;
2511                                 result_dir = m_dir;
2512                                 // Randomize next direction
2513                                 randomizeDir();
2514                                 return true;
2515                         }
2516                         /*
2517                                 Determine where to move next
2518                         */
2519                         // Jump one up if the actual space is there
2520                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
2521                                         == CONTENT_COBBLE
2522                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
2523                                         == CONTENT_AIR
2524                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).d
2525                                         == CONTENT_AIR)
2526                                 p += v3s16(0,1,0);
2527                         // Jump one down if the actual space is there
2528                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
2529                                         == CONTENT_COBBLE
2530                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
2531                                         == CONTENT_AIR
2532                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).d
2533                                         == CONTENT_AIR)
2534                                 p += v3s16(0,-1,0);
2535                         // Check if walking is now possible
2536                         if(vmanip.getNodeNoExNoEmerge(p).d
2537                                         != CONTENT_AIR
2538                         || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
2539                                         != CONTENT_AIR)
2540                         {
2541                                 // Cannot continue walking here
2542                                 randomizeDir();
2543                                 continue;
2544                         }
2545                         // Move there
2546                         m_pos = p;
2547                 }
2548                 return false;
2549         }
2550
2551         bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
2552                         v3s16 &result_doordir, v3s16 &result_roomplace)
2553         {
2554                 for(s16 trycount=0; trycount<30; trycount++)
2555                 {
2556                         v3s16 doorplace;
2557                         v3s16 doordir;
2558                         bool r = findPlaceForDoor(doorplace, doordir);
2559                         if(r == false)
2560                                 continue;
2561                         v3s16 roomplace;
2562                         // X east, Z north, Y up
2563                         if(doordir == v3s16(1,0,0)) // X+
2564                                 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2+myrand_range(-roomsize.Z/2,roomsize.Z/2));
2565                         if(doordir == v3s16(-1,0,0)) // X-
2566                                 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2+myrand_range(-roomsize.Z/2,roomsize.Z/2));
2567                         if(doordir == v3s16(0,0,1)) // Z+
2568                                 roomplace = doorplace + v3s16(-roomsize.X/2+myrand_range(-roomsize.X/2,roomsize.X/2),-1,0);
2569                         if(doordir == v3s16(0,0,-1)) // Z-
2570                                 roomplace = doorplace + v3s16(-roomsize.X/2+myrand_range(-roomsize.X/2,roomsize.X/2),-1,-roomsize.Z+1);
2571                         
2572                         // Check fit
2573                         bool fits = true;
2574                         for(s16 z=1; z<roomsize.Z-1; z++)
2575                         for(s16 y=1; y<roomsize.Y-1; y++)
2576                         for(s16 x=1; x<roomsize.X-1; x++)
2577                         {
2578                                 v3s16 p = roomplace + v3s16(x,y,z);
2579                                 if(vmanip.m_area.contains(p) == false)
2580                                 {
2581                                         fits = false;
2582                                         break;
2583                                 }
2584                                 if(vmanip.m_flags[vmanip.m_area.index(p)]
2585                                                 & VMANIP_FLAG_DUNGEON_INSIDE)
2586                                 {
2587                                         fits = false;
2588                                         break;
2589                                 }
2590                         }
2591                         if(fits == false)
2592                         {
2593                                 // Find new place
2594                                 continue;
2595                         }
2596                         result_doorplace = doorplace;
2597                         result_doordir = doordir;
2598                         result_roomplace = roomplace;
2599                         return true;
2600                 }
2601                 return false;
2602         }
2603
2604 private:
2605         VoxelManipulator &vmanip;
2606         v3s16 m_pos;
2607         v3s16 m_dir;    
2608 };
2609
2610 void make_dungeon1(VoxelManipulator &vmanip)
2611 {
2612         v3s16 areasize = vmanip.m_area.getExtent();
2613         v3s16 roomsize;
2614         v3s16 roomplace;
2615         
2616         roomsize = v3s16(myrand_range(4,8),myrand_range(4,6),myrand_range(4,8));
2617         roomplace = vmanip.m_area.MinEdge + v3s16(
2618                         myrand_range(0,areasize.X-roomsize.X-1),
2619                         myrand_range(0,areasize.Y-roomsize.Y-1),
2620                         myrand_range(0,areasize.Z-roomsize.Z-1));
2621         
2622         u32 room_count = myrand_range(2,7);
2623         for(u32 i=0; i<room_count; i++)
2624         {
2625                 make_room1(vmanip, roomsize, roomplace);
2626
2627                 RoomWalker walker(vmanip, roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2));
2628                 v3s16 doorplace;
2629                 v3s16 doordir;
2630                 bool r = walker.findPlaceForDoor(doorplace, doordir);
2631                 if(r == false)
2632                 {
2633                         //dstream<<"walker.findPlaceForDoor failed"<<std::endl;
2634                         return;
2635                 }
2636                 //dstream<<"walker.findPlaceForDoor succeeded"<<std::endl;
2637                 
2638                 make_door1(vmanip, doorplace, doordir);
2639
2640                 v3s16 corridor_end;
2641                 v3s16 corridor_end_dir;
2642                 make_corridor(vmanip, doorplace, doordir, corridor_end, corridor_end_dir);
2643                 
2644                 roomsize = v3s16(myrand_range(4,8),myrand_range(4,6),myrand_range(4,8));
2645                 walker.setPos(corridor_end);
2646                 walker.setDir(corridor_end_dir);
2647                 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
2648                 if(r == false)
2649                 {
2650                         //dstream<<"walker.findPlaceForRoomDoor failed"<<std::endl;
2651                         return;
2652                 }
2653                 //dstream<<"walker.findPlaceForRoomDoor succeeded"<<std::endl;
2654                 make_door1(vmanip, doorplace, doordir);
2655         }
2656         
2657         make_room1(vmanip, roomsize, roomplace);
2658         
2659 }
2660
2661 /*
2662         Noise functions. Make sure seed is mangled differently in each one.
2663 */
2664
2665 // This affects the shape of the contour
2666 //#define CAVE_NOISE_SCALE 10.0
2667 #define CAVE_NOISE_SCALE 5.0
2668
2669 NoiseParams get_cave_noise1_params(u64 seed)
2670 {
2671         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
2672                         200, CAVE_NOISE_SCALE);*/
2673         return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
2674                         100, CAVE_NOISE_SCALE);
2675 }
2676
2677 NoiseParams get_cave_noise2_params(u64 seed)
2678 {
2679         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
2680                         200, CAVE_NOISE_SCALE);*/
2681         return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
2682                         100, CAVE_NOISE_SCALE);
2683 }
2684
2685 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
2686 #define CAVE_NOISE_THRESHOLD (2.0/CAVE_NOISE_SCALE)
2687
2688 NoiseParams get_ground_noise1_params(u64 seed)
2689 {
2690         return NoiseParams(NOISE_PERLIN, seed+983240, 5,
2691                         0.60, 100.0, 30.0);
2692 }
2693
2694 NoiseParams get_ground_crumbleness_params(u64 seed)
2695 {
2696         return NoiseParams(NOISE_PERLIN, seed+34413, 3,
2697                         1.3, 20.0, 1.0);
2698 }
2699
2700 NoiseParams get_ground_wetness_params(u64 seed)
2701 {
2702         return NoiseParams(NOISE_PERLIN, seed+32474, 4,
2703                         1.1, 40.0, 1.0);
2704 }
2705
2706 bool is_cave(u64 seed, v3s16 p)
2707 {
2708         double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
2709         double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
2710         return d1*d2 > CAVE_NOISE_THRESHOLD;
2711 }
2712
2713 /*
2714         Ground density noise shall be interpreted by using this.
2715
2716         TODO: No perlin noises here, they should be outsourced
2717               and buffered
2718 */
2719 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
2720 {
2721         //return ((double)p.Y < ground_noise1_val);
2722
2723         double f = 1.0 + noise2d_perlin(
2724                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
2725                         seed+920381, 3, 0.5);
2726         if(f < 0.01)
2727                 f = 0.01;
2728         else if(f >= 1.0)
2729                 f *= 2.0;
2730         double h = WATER_LEVEL + 10 * noise2d_perlin(
2731                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
2732                         seed+84174, 4, 0.5);
2733         return ((double)p.Y - h < ground_noise1_val * f);
2734 }
2735
2736 /*
2737         Queries whether a position is ground or not.
2738 */
2739 bool is_ground(u64 seed, v3s16 p)
2740 {
2741         double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
2742         return val_is_ground(val1, p, seed);
2743 }
2744
2745 // Amount of trees per area in nodes
2746 double tree_amount_2d(u64 seed, v2s16 p)
2747 {
2748         /*double noise = noise2d_perlin(
2749                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
2750                         seed+2, 5, 0.66);*/
2751         double noise = noise2d_perlin(
2752                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
2753                         seed+2, 4, 0.66);
2754         double zeroval = -0.35;
2755         if(noise < zeroval)
2756                 return 0;
2757         else
2758                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
2759 }
2760
2761 #if 0
2762 double randomstone_amount_2d(u64 seed, v2s16 p)
2763 {
2764         double noise = noise2d_perlin(
2765                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
2766                         seed+3829434, 5, 0.66);
2767         double zeroval = 0.1;
2768         if(noise < zeroval)
2769                 return 0;
2770         else
2771                 return 0.01 * (noise-zeroval) / (1.0-zeroval);
2772 }
2773 #endif
2774
2775 double largestone_amount_2d(u64 seed, v2s16 p)
2776 {
2777         double noise = noise2d_perlin(
2778                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
2779                         seed+14143242, 5, 0.66);
2780         double zeroval = 0.3;
2781         if(noise < zeroval)
2782                 return 0;
2783         else
2784                 return 0.005 * (noise-zeroval) / (1.0-zeroval);
2785 }
2786
2787 /*
2788         Incrementally find ground level from 3d noise
2789 */
2790 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
2791 {
2792         // Start a bit fuzzy to make averaging lower precision values
2793         // more useful
2794         s16 level = myrand_range(-precision/2, precision/2);
2795         s16 dec[] = {31000, 100, 20, 4, 1, 0};
2796         s16 i;
2797         for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
2798         {
2799                 // First find non-ground by going upwards
2800                 // Don't stop in caves.
2801                 {
2802                         s16 max = level+dec[i-1]*2;
2803                         v3s16 p(p2d.X, level, p2d.Y);
2804                         for(; p.Y < max; p.Y += dec[i])
2805                         {
2806                                 if(!is_ground(seed, p))
2807                                 {
2808                                         level = p.Y;
2809                                         break;
2810                                 }
2811                         }
2812                 }
2813                 // Then find ground by going downwards from there.
2814                 // Go in caves, too, when precision is 1.
2815                 {
2816                         s16 min = level-dec[i-1]*2;
2817                         v3s16 p(p2d.X, level, p2d.Y);
2818                         for(; p.Y>min; p.Y-=dec[i])
2819                         {
2820                                 bool ground = is_ground(seed, p);
2821                                 /*if(dec[i] == 1 && is_cave(seed, p))
2822                                         ground = false;*/
2823                                 if(ground)
2824                                 {
2825                                         level = p.Y;
2826                                         break;
2827                                 }
2828                         }
2829                 }
2830         }
2831         
2832         // This is more like the actual ground level
2833         level += dec[i-1]/2;
2834
2835         return level;
2836 }
2837
2838 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
2839
2840 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
2841 {
2842         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
2843         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
2844         double a = 0;
2845         a += find_ground_level_from_noise(seed,
2846                         v2s16(node_min.X, node_min.Y), p);
2847         a += find_ground_level_from_noise(seed,
2848                         v2s16(node_min.X, node_max.Y), p);
2849         a += find_ground_level_from_noise(seed,
2850                         v2s16(node_max.X, node_max.Y), p);
2851         a += find_ground_level_from_noise(seed,
2852                         v2s16(node_max.X, node_min.Y), p);
2853         a += find_ground_level_from_noise(seed,
2854                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
2855         a /= 5;
2856         return a;
2857 }
2858
2859 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
2860
2861 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
2862 {
2863         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
2864         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
2865         double a = -31000;
2866         a = MYMAX(a, find_ground_level_from_noise(seed,
2867                         v2s16(node_min.X, node_min.Y), p));
2868         a = MYMAX(a, find_ground_level_from_noise(seed,
2869                         v2s16(node_min.X, node_max.Y), p));
2870         a = MYMAX(a, find_ground_level_from_noise(seed,
2871                         v2s16(node_max.X, node_max.Y), p));
2872         a = MYMAX(a, find_ground_level_from_noise(seed,
2873                         v2s16(node_min.X, node_min.Y), p));
2874         a = MYMAX(a, find_ground_level_from_noise(seed,
2875                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
2876         return a;
2877 }
2878
2879 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
2880
2881 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
2882 {
2883         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
2884         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
2885         double a = 31000;
2886         a = MYMIN(a, find_ground_level_from_noise(seed,
2887                         v2s16(node_min.X, node_min.Y), p));
2888         a = MYMIN(a, find_ground_level_from_noise(seed,
2889                         v2s16(node_min.X, node_max.Y), p));
2890         a = MYMIN(a, find_ground_level_from_noise(seed,
2891                         v2s16(node_max.X, node_max.Y), p));
2892         a = MYMIN(a, find_ground_level_from_noise(seed,
2893                         v2s16(node_min.X, node_min.Y), p));
2894         a = MYMIN(a, find_ground_level_from_noise(seed,
2895                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
2896         return a;
2897 }
2898
2899 #if 0
2900 #define AVERAGE_MUD_AMOUNT 4
2901
2902 double base_rock_level_2d(u64 seed, v2s16 p)
2903 {
2904         // The base ground level
2905         double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
2906                         + 20. * noise2d_perlin(
2907                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2908                         (seed>>32)+654879876, 6, 0.6);
2909
2910         /*// A bit hillier one
2911         double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
2912                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2913                         (seed>>27)+90340, 6, 0.69);
2914         if(base2 > base)
2915                 base = base2;*/
2916 #if 1
2917         // Higher ground level
2918         double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
2919                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2920                         seed+85039, 5, 0.69);
2921         //higher = 30; // For debugging
2922
2923         // Limit higher to at least base
2924         if(higher < base)
2925                 higher = base;
2926
2927         // Steepness factor of cliffs
2928         double b = 1.0 + 1.0 * noise2d_perlin(
2929                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2930                         seed-932, 7, 0.7);
2931         b = rangelim(b, 0.0, 1000.0);
2932         b = pow(b, 5);
2933         b *= 7;
2934         b = rangelim(b, 3.0, 1000.0);
2935         //dstream<<"b="<<b<<std::endl;
2936         //double b = 20;
2937
2938         // Offset to more low
2939         double a_off = -0.2;
2940         // High/low selector
2941         /*double a = 0.5 + b * (a_off + noise2d_perlin(
2942                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
2943                         seed-359, 6, 0.7));*/
2944         double a = (double)0.5 + b * (a_off + noise2d_perlin(
2945                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
2946                         seed-359, 5, 0.60));
2947         // Limit
2948         a = rangelim(a, 0.0, 1.0);
2949
2950         //dstream<<"a="<<a<<std::endl;
2951
2952         double h = base*(1.0-a) + higher*a;
2953 #else
2954         double h = base;
2955 #endif
2956         return h;
2957 }
2958
2959 double get_mud_add_amount(u64 seed, v2s16 p)
2960 {
2961         return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
2962                         0.5+(float)p.X/200, 0.5+(float)p.Y/200,
2963                         seed+91013, 3, 0.55));
2964 }
2965 #endif
2966
2967 bool get_have_sand(u64 seed, v2s16 p2d)
2968 {
2969         // Determine whether to have sand here
2970         double sandnoise = noise2d_perlin(
2971                         0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
2972                         seed+59420, 3, 0.50);
2973
2974         return (sandnoise > -0.15);
2975 }
2976
2977 /*
2978         Adds random objects to block, depending on the content of the block
2979 */
2980 void addRandomObjects(MapBlock *block)
2981 {
2982         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2983         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2984         {
2985                 bool last_node_walkable = false;
2986                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2987                 {
2988                         v3s16 p(x0,y0,z0);
2989                         MapNode n = block->getNodeNoEx(p);
2990                         if(n.d == CONTENT_IGNORE)
2991                                 continue;
2992                         if(content_features(n.d).liquid_type != LIQUID_NONE)
2993                                 continue;
2994                         if(content_features(n.d).walkable)
2995                         {
2996                                 last_node_walkable = true;
2997                                 continue;
2998                         }
2999                         if(last_node_walkable)
3000                         {
3001                                 // If block contains light information
3002                                 if(content_features(n.d).param_type == CPT_LIGHT)
3003                                 {
3004                                         if(n.getLight(LIGHTBANK_DAY) <= 3)
3005                                         {
3006                                                 if(myrand() % 300 == 0)
3007                                                 {
3008                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
3009                                                         pos_f.Y -= BS*0.4;
3010                                                         ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
3011                                                         std::string data = obj->getStaticData();
3012                                                         StaticObject s_obj(obj->getType(),
3013                                                                         obj->getBasePosition(), data);
3014                                                         // Add some
3015                                                         block->m_static_objects.insert(0, s_obj);
3016                                                         block->m_static_objects.insert(0, s_obj);
3017                                                         block->m_static_objects.insert(0, s_obj);
3018                                                         block->m_static_objects.insert(0, s_obj);
3019                                                         block->m_static_objects.insert(0, s_obj);
3020                                                         block->m_static_objects.insert(0, s_obj);
3021                                                         delete obj;
3022                                                 }
3023                                                 if(myrand() % 300 == 0)
3024                                                 {
3025                                                         v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
3026                                                         pos_f.Y -= BS*0.4;
3027                                                         ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
3028                                                         std::string data = obj->getStaticData();
3029                                                         StaticObject s_obj(obj->getType(),
3030                                                                         obj->getBasePosition(), data);
3031                                                         // Add one
3032                                                         block->m_static_objects.insert(0, s_obj);
3033                                                         delete obj;
3034                                                 }
3035                                         }
3036                                 }
3037                         }
3038                         last_node_walkable = false;
3039                 }
3040         }
3041         block->setChangedFlag();
3042 }
3043
3044 void makeBlock(BlockMakeData *data)
3045 {
3046         if(data->no_op)
3047         {
3048                 dstream<<"makeBlock: no-op"<<std::endl;
3049                 return;
3050         }
3051
3052         v3s16 blockpos = data->blockpos;
3053         
3054         /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
3055                         <<blockpos.Z<<")"<<std::endl;*/
3056
3057         ManualMapVoxelManipulator &vmanip = data->vmanip;
3058         v3s16 blockpos_min = blockpos - v3s16(1,1,1);
3059         v3s16 blockpos_max = blockpos + v3s16(1,1,1);
3060         // Area of center block
3061         v3s16 node_min = blockpos*MAP_BLOCKSIZE;
3062         v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
3063         // Full allocated area
3064         v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
3065         v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
3066         // Area of a block
3067         double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
3068
3069         v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
3070
3071         /*
3072                 Get average ground level from noise
3073         */
3074         
3075         s16 approx_groundlevel = (s16)get_sector_average_ground_level(
3076                         data->seed, v2s16(blockpos.X, blockpos.Z));
3077         //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
3078         
3079         s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
3080         
3081         /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
3082                         data->seed, v2s16(blockpos.X, blockpos.Z));
3083         // Minimum amount of ground above the central block
3084         s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;*/
3085         
3086         s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
3087                         data->seed, v2s16(blockpos.X, blockpos.Z), 1);
3088         // Minimum amount of ground above the central block
3089         s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
3090         
3091         /*
3092                 Special case for high air or water
3093         */
3094         if(maximum_ground_depth < -20)
3095         {
3096                 for(s16 x=node_min.X; x<=node_max.X; x++)
3097                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
3098                 {
3099                         // Node position
3100                         v2s16 p2d(x,z);
3101                         {
3102                                 // Use fast index incrementing
3103                                 v3s16 em = vmanip.m_area.getExtent();
3104                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
3105                                 for(s16 y=node_min.Y; y<=node_max.Y; y++)
3106                                 {
3107                                         // Only modify places that have no content
3108                                         if(vmanip.m_data[i].d == CONTENT_IGNORE)
3109                                         {
3110                                                 if(y <= WATER_LEVEL)
3111                                                         vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
3112                                                 else
3113                                                         vmanip.m_data[i] = MapNode(CONTENT_AIR);
3114                                         }
3115                                 
3116                                         data->vmanip.m_area.add_y(em, i, 1);
3117                                 }
3118                         }
3119                 }
3120                 
3121                 // We're done
3122                 return;
3123         }
3124         
3125         /*
3126                 Make some 3D noise
3127         */
3128         
3129         //NoiseBuffer noisebuf1;
3130         //NoiseBuffer noisebuf2;
3131         NoiseBuffer noisebuf_cave;
3132         NoiseBuffer noisebuf_ground;
3133         NoiseBuffer noisebuf_ground_crumbleness;
3134         NoiseBuffer noisebuf_ground_wetness;
3135         {
3136                 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
3137                 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
3138
3139                 //TimeTaker timer("noisebuf.create");
3140
3141                 /*
3142                         Cave noise
3143                 */
3144
3145                 noisebuf_cave.create(get_cave_noise1_params(data->seed),
3146                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
3147                                 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
3148                                 4, 4, 4);
3149                                 //3.5, 3.5, 3.5);
3150                 
3151                 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
3152
3153                 /*
3154                         Ground noise
3155                 */
3156                 
3157                 // Sample length
3158                 v3f sl = v3f(4.0, 4.0, 4.0);
3159                 
3160                 /*
3161                         Density
3162                 */
3163                 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
3164                 noisebuf_ground.create(get_ground_noise1_params(data->seed),
3165                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
3166                                 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
3167                                 sl.X, sl.Y, sl.Z);
3168                 
3169                 /*
3170                         Content
3171                 */
3172                 sl = v3f(2.5, 2.5, 2.5);
3173                 noisebuf_ground_crumbleness.create(
3174                                 get_ground_crumbleness_params(data->seed),
3175                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
3176                                 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
3177                                 sl.X, sl.Y, sl.Z);
3178                 noisebuf_ground_wetness.create(
3179                                 get_ground_wetness_params(data->seed),
3180                                 minpos_f.X, minpos_f.Y, minpos_f.Z,
3181                                 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
3182                                 sl.X, sl.Y, sl.Z);
3183         }
3184         
3185         /*
3186                 Make base ground level
3187         */
3188
3189         for(s16 x=node_min.X; x<=node_max.X; x++)
3190         for(s16 z=node_min.Z; z<=node_max.Z; z++)
3191         {
3192                 // Node position
3193                 v2s16 p2d(x,z);
3194                 {
3195                         // Use fast index incrementing
3196                         v3s16 em = vmanip.m_area.getExtent();
3197                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
3198                         for(s16 y=node_min.Y; y<=node_max.Y; y++)
3199                         {
3200                                 // Only modify places that have no content
3201                                 if(vmanip.m_data[i].d == CONTENT_IGNORE)
3202                                 {
3203                                         if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
3204                                                 vmanip.m_data[i] = MapNode(CONTENT_AIR);
3205                                         else if(val_is_ground(noisebuf_ground.get(x,y,z),
3206                                                         v3s16(x,y,z), data->seed))
3207                                                 vmanip.m_data[i] = MapNode(CONTENT_STONE);
3208                                         else if(y <= WATER_LEVEL)
3209                                                 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
3210                                         else
3211                                                 vmanip.m_data[i] = MapNode(CONTENT_AIR);
3212                                 }
3213
3214                                 /*if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
3215                                 {
3216                                         // Only modify places that have no content
3217                                         if(vmanip.m_data[i].d == CONTENT_IGNORE)
3218                                                 vmanip.m_data[i] = MapNode(CONTENT_AIR);
3219                                 }
3220                                 else if(is_ground(noisebuf_ground.get(x,y,z), y))
3221                                 {
3222                                         // Only modify places that have no content
3223                                         if(vmanip.m_data[i].d == CONTENT_IGNORE)
3224                                                 vmanip.m_data[i] = MapNode(CONTENT_STONE);
3225                                 }
3226                                 else if(y <= WATER_LEVEL)
3227                                 {
3228                                         // Only modify places that have air or no content
3229                                         if(vmanip.m_data[i].d == CONTENT_IGNORE
3230                                                         || vmanip.m_data[i].d == CONTENT_AIR)
3231                                         vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
3232                                 }
3233                                 else
3234                                 {
3235                                         // Only modify places that have no content
3236                                         if(vmanip.m_data[i].d == CONTENT_IGNORE)
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         /*
3246                 Add minerals
3247         */
3248
3249         {
3250                 /*
3251                         Add meseblocks
3252                 */
3253                 for(s16 i=0; i<approx_ground_depth/4; i++)
3254                 {
3255                         if(myrand()%50 == 0)
3256                         {
3257                                 s16 x = myrand_range(node_min.X+1, node_max.X-1);
3258                                 s16 y = myrand_range(node_min.Y+1, node_max.Y-1);
3259                                 s16 z = myrand_range(node_min.Z+1, node_max.Z-1);
3260                                 for(u16 i=0; i<27; i++)
3261                                 {
3262                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3263                                         u32 vi = vmanip.m_area.index(p);
3264                                         if(vmanip.m_data[vi].d == CONTENT_STONE)
3265                                                 if(myrand()%8 == 0)
3266                                                         vmanip.m_data[vi] = MapNode(CONTENT_MESE);
3267                                 }
3268                                         
3269                         }
3270                 }
3271                 /*
3272                         Add others
3273                 */
3274                 {
3275                         u16 a = myrand_range(0,15);
3276                         a = a*a*a;
3277                         u16 amount = 20 * a/1000;
3278                         for(s16 i=0; i<amount; i++)
3279                         {
3280                                 s16 x = myrand_range(node_min.X+1, node_max.X-1);
3281                                 s16 y = myrand_range(node_min.Y+1, node_max.Y-1);
3282                                 s16 z = myrand_range(node_min.Z+1, node_max.Z-1);
3283
3284                                 u8 base_content = CONTENT_STONE;
3285                                 MapNode new_content(CONTENT_IGNORE);
3286                                 u32 sparseness = 6;
3287
3288                                 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
3289                                 {
3290                                         new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
3291                                 }
3292                                 else
3293                                 {
3294                                         if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
3295                                                 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
3296                                         /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
3297                                                 vmanip.m_data[i] = MapNode(CONTENT_MUD);
3298                                         else
3299                                                 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
3300                                 }
3301                                 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
3302                                 {
3303                                 }*/
3304
3305                                 if(new_content.d != CONTENT_IGNORE)
3306                                 {
3307                                         for(u16 i=0; i<27; i++)
3308                                         {
3309                                                 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3310                                                 u32 vi = vmanip.m_area.index(p);
3311                                                 if(vmanip.m_data[vi].d == base_content)
3312                                                 {
3313                                                         if(myrand()%sparseness == 0)
3314                                                                 vmanip.m_data[vi] = new_content;
3315                                                 }
3316                                         }
3317                                 }
3318                         }
3319                 }
3320                 /*
3321                         Add coal
3322                 */
3323                 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
3324                 //for(s16 i=0; i<50; i++)
3325                 u16 coal_amount = 30;
3326                 u16 coal_rareness = 60 / coal_amount;
3327                 if(coal_rareness == 0)
3328                         coal_rareness = 1;
3329                 if(myrand()%coal_rareness == 0)
3330                 {
3331                         u16 a = myrand() % 16;
3332                         u16 amount = coal_amount * a*a*a / 1000;
3333                         for(s16 i=0; i<amount; i++)
3334                         {
3335                                 s16 x = myrand_range(node_min.X+1, node_max.X-1);
3336                                 s16 y = myrand_range(node_min.Y+1, node_max.Y-1);
3337                                 s16 z = myrand_range(node_min.Z+1, node_max.Z-1);
3338                                 for(u16 i=0; i<27; i++)
3339                                 {
3340                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3341                                         u32 vi = vmanip.m_area.index(p);
3342                                         if(vmanip.m_data[vi].d == CONTENT_STONE)
3343                                                 if(myrand()%8 == 0)
3344                                                         vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
3345                                 }
3346                         }
3347                 }
3348                 /*
3349                         Add iron
3350                 */
3351                 u16 iron_amount = 8;
3352                 u16 iron_rareness = 60 / iron_amount;
3353                 if(iron_rareness == 0)
3354                         iron_rareness = 1;
3355                 if(myrand()%iron_rareness == 0)
3356                 {
3357                         u16 a = myrand() % 16;
3358                         u16 amount = iron_amount * a*a*a / 1000;
3359                         for(s16 i=0; i<amount; i++)
3360                         {
3361                                 s16 x = myrand_range(node_min.X+1, node_max.X-1);
3362                                 s16 y = myrand_range(node_min.Y+1, node_max.Y-1);
3363                                 s16 z = myrand_range(node_min.Z+1, node_max.Z-1);
3364                                 for(u16 i=0; i<27; i++)
3365                                 {
3366                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3367                                         u32 vi = vmanip.m_area.index(p);
3368                                         if(vmanip.m_data[vi].d == CONTENT_STONE)
3369                                                 if(myrand()%8 == 0)
3370                                                         vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
3371                                 }
3372                         }
3373                 }
3374         }
3375
3376         /*
3377                 Add mud and sand and others underground (in place of stone)
3378         */
3379
3380         for(s16 x=node_min.X; x<=node_max.X; x++)
3381         for(s16 z=node_min.Z; z<=node_max.Z; z++)
3382         {
3383                 // Node position
3384                 v2s16 p2d(x,z);
3385                 {
3386                         // Use fast index incrementing
3387                         v3s16 em = vmanip.m_area.getExtent();
3388                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
3389                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
3390                         {
3391                                 if(vmanip.m_data[i].d == CONTENT_STONE)
3392                                 {
3393                                         if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
3394                                         {
3395                                                 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
3396                                                         vmanip.m_data[i] = MapNode(CONTENT_MUD);
3397                                                 else
3398                                                         vmanip.m_data[i] = MapNode(CONTENT_SAND);
3399                                         }
3400                                         else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
3401                                         {
3402                                                 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
3403                                                         vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
3404                                         }
3405                                 }
3406
3407                                 data->vmanip.m_area.add_y(em, i, -1);
3408                         }
3409                 }
3410         }
3411
3412         /*
3413                 Add dungeons
3414         */
3415         
3416         //if(node_min.Y < approx_groundlevel)
3417         //if(myrand() % 3 == 0)
3418         //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
3419         if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
3420         {
3421                 // Dungeon generator doesn't modify places which have this set
3422                 data->vmanip.clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
3423                                 | VMANIP_FLAG_DUNGEON_PRESERVE);
3424                 
3425                 // Set all air and water to be untouchable to make dungeons open
3426                 // to caves and open air
3427                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
3428                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
3429                 {
3430                         // Node position
3431                         v2s16 p2d(x,z);
3432                         {
3433                                 // Use fast index incrementing
3434                                 v3s16 em = vmanip.m_area.getExtent();
3435                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
3436                                 for(s16 y=node_max.Y; y>=full_node_min.Y; y--)
3437                                 {
3438                                         if(vmanip.m_data[i].d == CONTENT_AIR)
3439                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
3440                                         else if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
3441                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
3442                                         data->vmanip.m_area.add_y(em, i, -1);
3443                                 }
3444                         }
3445                 }
3446                 
3447                 /*s16 x = myrand_range(node_min.X, node_max.X);
3448                 s16 z = myrand_range(node_min.Z, node_max.Z);
3449                 s16 y = myrand_range(node_min.Y, node_max.Y);*/
3450                 // Add it
3451                 make_dungeon1(data->vmanip);
3452                 
3453                 // Take different seed for every dungeon for not blending their
3454                 // mossyness together
3455                 //u32 mossyseed = z*38134234+y*42123+x*23;
3456                 u32 mossyseed = full_node_min.Z*38134234
3457                                 +full_node_min.Y*42123+full_node_min.X*23;
3458
3459                 // Convert some cobble to mossy cobble
3460                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
3461                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
3462                 {
3463                         // Node position
3464                         v2s16 p2d(x,z);
3465                         {
3466                                 // Use fast index incrementing
3467                                 v3s16 em = vmanip.m_area.getExtent();
3468                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
3469                                 for(s16 y=node_max.Y; y>=full_node_min.Y; y--)
3470                                 {
3471                                         // No mossy in dry places
3472                                         // (noisebuf not used because it's smaller in size)
3473                                         if(noise3d_param(get_ground_wetness_params(data->seed), x,y,z)
3474                                                         < -0.6)
3475                                                 continue;
3476                                         double d = noise3d_perlin((float)x/4.,
3477                                                         (float)y/4.,(float)z/4.,
3478                                                         mossyseed, 2, 0.9);
3479                                         if(d < 0.0)
3480                                                 continue;
3481                                         if(vmanip.m_data[i].d == CONTENT_COBBLE)
3482                                                 vmanip.m_data[i].d = CONTENT_MOSSYCOBBLE;
3483                                         data->vmanip.m_area.add_y(em, i, -1);
3484                                 }
3485                         }
3486                 }
3487         }
3488         
3489         /*
3490                 Add top and bottom side of water to transforming_liquid queue
3491         */
3492
3493         for(s16 x=node_min.X; x<=node_max.X; x++)
3494         for(s16 z=node_min.Z; z<=node_max.Z; z++)
3495         {
3496                 // Node position
3497                 v2s16 p2d(x,z);
3498                 {
3499                         bool water_found = false;
3500                         // Use fast index incrementing
3501                         v3s16 em = vmanip.m_area.getExtent();
3502                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
3503                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
3504                         {
3505                                 if(water_found == false)
3506                                 {
3507                                         if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
3508                                         {
3509                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
3510                                                 data->transforming_liquid.push_back(p);
3511                                                 water_found = true;
3512                                         }
3513                                 }
3514                                 else
3515                                 {
3516                                         // This can be done because water_found can only
3517                                         // turn to true and end up here after going through
3518                                         // a single block.
3519                                         if(vmanip.m_data[i+1].d != CONTENT_WATERSOURCE)
3520                                         {
3521                                                 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
3522                                                 data->transforming_liquid.push_back(p);
3523                                                 water_found = false;
3524                                         }
3525                                 }
3526
3527                                 data->vmanip.m_area.add_y(em, i, -1);
3528                         }
3529                 }
3530         }
3531
3532         /*
3533                 If close to ground level
3534         */
3535
3536         if(abs(approx_ground_depth) < 20)
3537         {
3538                 /*
3539                         Add grass and mud
3540                 */
3541
3542                 for(s16 x=node_min.X; x<=node_max.X; x++)
3543                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
3544                 {
3545                         // Node position
3546                         v2s16 p2d(x,z);
3547                         {
3548                                 bool possibly_have_sand = get_have_sand(data->seed, p2d);
3549                                 bool have_sand = false;
3550                                 u32 mud_count = 0;
3551                                 bool air_detected = false;
3552                                 bool water_detected = false;
3553                                 // Use fast index incrementing
3554                                 s16 start_y = node_max.Y+2;
3555                                 v3s16 em = vmanip.m_area.getExtent();
3556                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
3557                                 for(s16 y=start_y; y>=node_min.Y-2; y--)
3558                                 {
3559                                         if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
3560                                                 water_detected = true;
3561                                         if(vmanip.m_data[i].d == CONTENT_AIR)
3562                                                 air_detected = true;
3563
3564                                         if((vmanip.m_data[i].d == CONTENT_STONE
3565                                                         || vmanip.m_data[i].d == CONTENT_GRASS
3566                                                         || vmanip.m_data[i].d == CONTENT_MUD
3567                                                         || vmanip.m_data[i].d == CONTENT_SAND
3568                                                         || vmanip.m_data[i].d == CONTENT_GRAVEL
3569                                                         ) && (air_detected || water_detected))
3570                                         {
3571                                                 if(mud_count == 0 && y <= WATER_LEVEL+2
3572                                                                 && possibly_have_sand)
3573                                                         have_sand = true;
3574
3575                                                 if(have_sand)
3576                                                 {
3577                                                         vmanip.m_data[i] = MapNode(CONTENT_SAND);
3578                                                 }
3579                                                 else if(mud_count==0 && !water_detected && y >= WATER_LEVEL)
3580                                                         vmanip.m_data[i] = MapNode(CONTENT_GRASS);
3581                                                 else
3582                                                         vmanip.m_data[i] = MapNode(CONTENT_MUD);
3583
3584                                                 mud_count++;
3585                                                 if(mud_count >= 4)
3586                                                         break;
3587                                         }
3588                                         else if(mud_count != 0)
3589                                                 break;
3590
3591                                         data->vmanip.m_area.add_y(em, i, -1);
3592                                 }
3593                         }
3594                 }
3595
3596                 /*
3597                         Add trees
3598                 */
3599                 
3600                 // Amount of trees
3601                 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
3602                 // Put trees in random places on part of division
3603                 for(u32 i=0; i<tree_count; i++)
3604                 {
3605                         s16 x = myrand_range(node_min.X, node_max.X);
3606                         s16 z = myrand_range(node_min.Z, node_max.Z);
3607                         //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
3608                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
3609                         // Don't make a tree under water level
3610                         if(y < WATER_LEVEL)
3611                                 continue;
3612                         // Make sure tree fits (only trees whose starting point is
3613                         // at this block are added)
3614                         if(y < node_min.Y || y > node_max.Y)
3615                                 continue;
3616                         /*
3617                                 Find exact ground level
3618                         */
3619                         v3s16 p(x,y+6,z);
3620                         bool found = false;
3621                         for(; p.Y >= y-6; p.Y--)
3622                         {
3623                                 u32 i = data->vmanip.m_area.index(p);
3624                                 MapNode *n = &data->vmanip.m_data[i];
3625                                 if(n->d != CONTENT_AIR && n->d != CONTENT_IGNORE)
3626                                 {
3627                                         found = true;
3628                                         break;
3629                                 }
3630                         }
3631                         // If not found, handle next one
3632                         if(found == false)
3633                                 continue;
3634                         /*
3635                                 Trees grow only on mud and grass
3636                         */
3637                         {
3638                                 u32 i = data->vmanip.m_area.index(p);
3639                                 MapNode *n = &data->vmanip.m_data[i];
3640                                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3641                                         continue;
3642                         }
3643                         // Tree will be placed one higher
3644                         p.Y++;
3645                         // Make a tree
3646                         make_tree(data->vmanip, p);
3647                 }
3648
3649 #if 0
3650                 /*
3651                         Add some kind of random stones
3652                 */
3653                 
3654                 u32 random_stone_count = block_area_nodes *
3655                                 randomstone_amount_2d(data->seed, p2d_center);
3656                 // Put in random places on part of division
3657                 for(u32 i=0; i<random_stone_count; i++)
3658                 {
3659                         s16 x = myrand_range(node_min.X, node_max.X);
3660                         s16 z = myrand_range(node_min.Z, node_max.Z);
3661                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
3662                         // Don't add under water level
3663                         /*if(y < WATER_LEVEL)
3664                                 continue;*/
3665                         // Don't add if doesn't belong to this block
3666                         if(y < node_min.Y || y > node_max.Y)
3667                                 continue;
3668                         v3s16 p(x,y,z);
3669                         // Filter placement
3670                         /*{
3671                                 u32 i = data->vmanip.m_area.index(v3s16(p));
3672                                 MapNode *n = &data->vmanip.m_data[i];
3673                                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3674                                         continue;
3675                         }*/
3676                         // Will be placed one higher
3677                         p.Y++;
3678                         // Add it
3679                         make_randomstone(data->vmanip, p);
3680                 }
3681 #endif
3682
3683 #if 0
3684                 /*
3685                         Add larger stones
3686                 */
3687                 
3688                 u32 large_stone_count = block_area_nodes *
3689                                 largestone_amount_2d(data->seed, p2d_center);
3690                 //u32 large_stone_count = 1;
3691                 // Put in random places on part of division
3692                 for(u32 i=0; i<large_stone_count; i++)
3693                 {
3694                         s16 x = myrand_range(node_min.X, node_max.X);
3695                         s16 z = myrand_range(node_min.Z, node_max.Z);
3696                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
3697                         // Don't add under water level
3698                         /*if(y < WATER_LEVEL)
3699                                 continue;*/
3700                         // Don't add if doesn't belong to this block
3701                         if(y < node_min.Y || y > node_max.Y)
3702                                 continue;
3703                         v3s16 p(x,y,z);
3704                         // Filter placement
3705                         /*{
3706                                 u32 i = data->vmanip.m_area.index(v3s16(p));
3707                                 MapNode *n = &data->vmanip.m_data[i];
3708                                 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3709                                         continue;
3710                         }*/
3711                         // Will be placed one lower
3712                         p.Y--;
3713                         // Add it
3714                         make_largestone(data->vmanip, p);
3715                 }
3716 #endif
3717         }
3718
3719 }
3720
3721 void ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
3722 {
3723         /*dstream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
3724                         <<blockpos.Z<<")"<<std::endl;*/
3725
3726         data->no_op = false;
3727         data->seed = m_seed;
3728         data->blockpos = blockpos;
3729
3730         /*
3731                 Create the whole area of this and the neighboring blocks
3732         */
3733         {
3734                 //TimeTaker timer("initBlockMake() create area");
3735                 
3736                 for(s16 x=-1; x<=1; x++)
3737                 for(s16 z=-1; z<=1; z++)
3738                 {
3739                         v2s16 sectorpos(blockpos.X+x, blockpos.Z+z);
3740                         // Sector metadata is loaded from disk if not already loaded.
3741                         ServerMapSector *sector = createSector(sectorpos);
3742                         assert(sector);
3743
3744                         for(s16 y=-1; y<=1; y++)
3745                         {
3746                                 MapBlock *block = createBlock(blockpos);
3747
3748                                 // Lighting won't be calculated
3749                                 block->setLightingExpired(true);
3750                                 // Lighting will be calculated
3751                                 //block->setLightingExpired(false);
3752
3753                                 /*
3754                                         Block gets sunlight if this is true.
3755
3756                                         This should be set to true when the top side of a block
3757                                         is completely exposed to the sky.
3758                                 */
3759                                 block->setIsUnderground(false);
3760                         }
3761                 }
3762         }
3763         
3764         /*
3765                 Now we have a big empty area.
3766
3767                 Make a ManualMapVoxelManipulator that contains this and the
3768                 neighboring blocks
3769         */
3770         
3771         v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
3772         v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
3773         
3774         data->vmanip.setMap(this);
3775
3776         // Add the area
3777         {
3778                 //TimeTaker timer("initBlockMake() initialEmerge");
3779                 data->vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
3780         }
3781
3782         // Data is ready now.
3783 }
3784
3785 MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
3786                 core::map<v3s16, MapBlock*> &changed_blocks)
3787 {
3788         v3s16 blockpos = data->blockpos;
3789         /*dstream<<"finishBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
3790                         <<blockpos.Z<<")"<<std::endl;*/
3791
3792         if(data->no_op)
3793         {
3794                 dstream<<"finishBlockMake(): no-op"<<std::endl;
3795                 return NULL;
3796         }
3797
3798         /*dstream<<"Resulting vmanip:"<<std::endl;
3799         data->vmanip.print(dstream);*/
3800         
3801         /*
3802                 Blit generated stuff to map
3803         */
3804         {
3805                 // 70ms @cs=8
3806                 //TimeTaker timer("finishBlockMake() blitBackAll");
3807                 data->vmanip.blitBackAll(&changed_blocks);
3808         }
3809
3810         //dstream<<"changed_blocks.size()="<<changed_blocks.size()<<std::endl;
3811
3812         /*
3813                 Copy transforming liquid information
3814         */
3815         while(data->transforming_liquid.size() > 0)
3816         {
3817                 v3s16 p = data->transforming_liquid.pop_front();
3818                 m_transforming_liquid.push_back(p);
3819         }
3820         
3821         /*
3822                 Get central block
3823         */
3824         MapBlock *block = getBlockNoCreateNoEx(data->blockpos);
3825         assert(block);
3826
3827         /*
3828                 Set is_underground flag for lighting with sunlight
3829         */
3830
3831         s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
3832                         data->seed, v2s16(blockpos.X, blockpos.Z));
3833         
3834         if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
3835                 block->setIsUnderground(true);
3836         else
3837                 block->setIsUnderground(false);
3838
3839         /*
3840                 Add sunlight to central block.
3841                 This makes in-dark-spawning monsters to not flood the whole thing.
3842                 Do not spread the light, though.
3843         */
3844         /*core::map<v3s16, bool> light_sources;
3845         bool black_air_left = false;
3846         block->propagateSunlight(light_sources, true, &black_air_left);*/
3847
3848         /*
3849                 NOTE: Lighting and object adding shouldn't really be here, but
3850                 lighting is a bit tricky to move properly to makeBlock.
3851                 TODO: Do this the right way anyway.
3852         */
3853
3854         /*
3855                 Update lighting
3856         */
3857         core::map<v3s16, MapBlock*> lighting_update_blocks;
3858         lighting_update_blocks.insert(block->getPos(), block);
3859         /*for(core::map<v3s16, MapBlock*>::Iterator
3860                         i = modified_blocks.getIterator();
3861                         i.atEnd() == false; i++)
3862         {
3863                 lighting_update_blocks.insert(i.getNode()->getKey(),
3864                                 i.getNode()->getValue());
3865         }*/
3866         updateLighting(lighting_update_blocks, changed_blocks);
3867         
3868         /*
3869                 Add random objects to block
3870         */
3871         addRandomObjects(block);
3872
3873         /*
3874                 Go through changed blocks
3875         */
3876         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
3877                         i.atEnd() == false; i++)
3878         {
3879                 MapBlock *block = i.getNode()->getValue();
3880                 assert(block);
3881                 /*
3882                         Update day/night difference cache of the MapBlocks
3883                 */
3884                 block->updateDayNightDiff();
3885                 /*
3886                         Set block as modified
3887                 */
3888                 block->raiseModified(MOD_STATE_WRITE_NEEDED);
3889         }
3890
3891         /*
3892                 Set central block as generated
3893         */
3894         block->setGenerated(true);
3895         
3896         /*
3897                 Save changed parts of map
3898                 NOTE: Will be saved later.
3899         */
3900         //save(true);
3901
3902         /*dstream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
3903                         <<blockpos.Z<<")"<<std::endl;*/
3904         
3905         return block;
3906 }
3907
3908 ServerMapSector * ServerMap::createSector(v2s16 p2d)
3909 {
3910         DSTACKF("%s: p2d=(%d,%d)",
3911                         __FUNCTION_NAME,
3912                         p2d.X, p2d.Y);
3913         
3914         /*
3915                 Check if it exists already in memory
3916         */
3917         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3918         if(sector != NULL)
3919                 return sector;
3920         
3921         /*
3922                 Try to load it from disk (with blocks)
3923         */
3924         //if(loadSectorFull(p2d) == true)
3925
3926         /*
3927                 Try to load metadata from disk
3928         */
3929         if(loadSectorMeta(p2d) == true)
3930         {
3931                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3932                 if(sector == NULL)
3933                 {
3934                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
3935                         throw InvalidPositionException("");
3936                 }
3937                 return sector;
3938         }
3939
3940         /*
3941                 Do not create over-limit
3942         */
3943         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3944         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3945         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3946         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
3947                 throw InvalidPositionException("createSector(): pos. over limit");
3948
3949         /*
3950                 Generate blank sector
3951         */
3952         
3953         sector = new ServerMapSector(this, p2d);
3954         
3955         // Sector position on map in nodes
3956         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
3957
3958         /*
3959                 Insert to container
3960         */
3961         m_sectors.insert(p2d, sector);
3962         
3963         return sector;
3964 }
3965
3966 /*
3967         This is a quick-hand function for calling makeBlock().
3968 */
3969 MapBlock * ServerMap::generateBlock(
3970                 v3s16 p,
3971                 core::map<v3s16, MapBlock*> &modified_blocks
3972 )
3973 {
3974         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
3975         
3976         /*dstream<<"generateBlock(): "
3977                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3978                         <<std::endl;*/
3979         
3980         //MapBlock *block = original_dummy;
3981                         
3982         v2s16 p2d(p.X, p.Z);
3983         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
3984         
3985         /*
3986                 Do not generate over-limit
3987         */
3988         if(blockpos_over_limit(p))
3989         {
3990                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
3991                 throw InvalidPositionException("generateBlock(): pos. over limit");
3992         }
3993
3994         /*
3995                 Create block make data
3996         */
3997         BlockMakeData data;
3998         initBlockMake(&data, p);
3999
4000         /*
4001                 Generate block
4002         */
4003         {
4004                 TimeTaker t("makeBlock()");
4005                 makeBlock(&data);
4006         }
4007
4008         /*
4009                 Blit data back on map, update lighting, add mobs and whatever this does
4010         */
4011         finishBlockMake(&data, modified_blocks);
4012
4013         /*
4014                 Get central block
4015         */
4016         MapBlock *block = getBlockNoCreateNoEx(p);
4017         assert(block);
4018
4019 #if 0
4020         /*
4021                 Check result
4022         */
4023         bool erroneus_content = false;
4024         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4025         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4026         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4027         {
4028                 v3s16 p(x0,y0,z0);
4029                 MapNode n = block->getNode(p);
4030                 if(n.d == CONTENT_IGNORE)
4031                 {
4032                         dstream<<"CONTENT_IGNORE at "
4033                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4034                                         <<std::endl;
4035                         erroneus_content = true;
4036                         assert(0);
4037                 }
4038         }
4039         if(erroneus_content)
4040         {
4041                 assert(0);
4042         }
4043 #endif
4044
4045 #if 0
4046         /*
4047                 Generate a completely empty block
4048         */
4049         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4050         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4051         {
4052                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4053                 {
4054                         MapNode n;
4055                         if(y0%2==0)
4056                                 n.d = CONTENT_AIR;
4057                         else
4058                                 n.d = CONTENT_STONE;
4059                         block->setNode(v3s16(x0,y0,z0), n);
4060                 }
4061         }
4062 #endif
4063
4064         return block;
4065 }
4066
4067 MapBlock * ServerMap::createBlock(v3s16 p)
4068 {
4069         DSTACKF("%s: p=(%d,%d,%d)",
4070                         __FUNCTION_NAME, p.X, p.Y, p.Z);
4071         
4072         /*
4073                 Do not create over-limit
4074         */
4075         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4076         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4077         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4078         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4079         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4080         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4081                 throw InvalidPositionException("createBlock(): pos. over limit");
4082         
4083         v2s16 p2d(p.X, p.Z);
4084         s16 block_y = p.Y;
4085         /*
4086                 This will create or load a sector if not found in memory.
4087                 If block exists on disk, it will be loaded.
4088
4089                 NOTE: On old save formats, this will be slow, as it generates
4090                       lighting on blocks for them.
4091         */
4092         ServerMapSector *sector;
4093         try{
4094                 sector = (ServerMapSector*)createSector(p2d);
4095                 assert(sector->getId() == MAPSECTOR_SERVER);
4096         }
4097         catch(InvalidPositionException &e)
4098         {
4099                 dstream<<"createBlock: createSector() failed"<<std::endl;
4100                 throw e;
4101         }
4102         /*
4103                 NOTE: This should not be done, or at least the exception
4104                 should not be passed on as std::exception, because it
4105                 won't be catched at all.
4106         */
4107         /*catch(std::exception &e)
4108         {
4109                 dstream<<"createBlock: createSector() failed: "
4110                                 <<e.what()<<std::endl;
4111                 throw e;
4112         }*/
4113
4114         /*
4115                 Try to get a block from the sector
4116         */
4117
4118         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4119         if(block)
4120         {
4121                 if(block->isDummy())
4122                         block->unDummify();
4123                 return block;
4124         }
4125         // Create blank
4126         block = sector->createBlankBlock(block_y);
4127         return block;
4128 }
4129
4130 #if 0
4131 MapBlock * ServerMap::emergeBlock(
4132                 v3s16 p,
4133                 bool only_from_disk,
4134                 core::map<v3s16, MapBlock*> &changed_blocks,
4135                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
4136 )
4137 {
4138         DSTACKF("%s: p=(%d,%d,%d), only_from_disk=%d",
4139                         __FUNCTION_NAME,
4140                         p.X, p.Y, p.Z, only_from_disk);
4141         
4142         // This has to be redone or removed
4143         assert(0);
4144         return NULL;
4145 }
4146 #endif
4147
4148 #if 0
4149         /*
4150                 Do not generate over-limit
4151         */
4152         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4153         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4154         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4155         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4156         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4157         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4158                 throw InvalidPositionException("emergeBlock(): pos. over limit");
4159         
4160         v2s16 p2d(p.X, p.Z);
4161         s16 block_y = p.Y;
4162         /*
4163                 This will create or load a sector if not found in memory.
4164                 If block exists on disk, it will be loaded.
4165         */
4166         ServerMapSector *sector;
4167         try{
4168                 sector = createSector(p2d);
4169                 //sector = emergeSector(p2d, changed_blocks);
4170         }
4171         catch(InvalidPositionException &e)
4172         {
4173                 dstream<<"emergeBlock: createSector() failed: "
4174                                 <<e.what()<<std::endl;
4175                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4176                                 <<std::endl
4177                                 <<"You could try to delete it."<<std::endl;
4178                 throw e;
4179         }
4180         catch(VersionMismatchException &e)
4181         {
4182                 dstream<<"emergeBlock: createSector() failed: "
4183                                 <<e.what()<<std::endl;
4184                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4185                                 <<std::endl
4186                                 <<"You could try to delete it."<<std::endl;
4187                 throw e;
4188         }
4189
4190         /*
4191                 Try to get a block from the sector
4192         */
4193
4194         bool does_not_exist = false;
4195         bool lighting_expired = false;
4196         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4197         
4198         // If not found, try loading from disk
4199         if(block == NULL)
4200         {
4201                 block = loadBlock(p);
4202         }
4203         
4204         // Handle result
4205         if(block == NULL)
4206         {
4207                 does_not_exist = true;
4208         }
4209         else if(block->isDummy() == true)
4210         {
4211                 does_not_exist = true;
4212         }
4213         else if(block->getLightingExpired())
4214         {
4215                 lighting_expired = true;
4216         }
4217         else
4218         {
4219                 // Valid block
4220                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
4221                 return block;
4222         }
4223         
4224         /*
4225                 If block was not found on disk and not going to generate a
4226                 new one, make sure there is a dummy block in place.
4227         */
4228         if(only_from_disk && (does_not_exist || lighting_expired))
4229         {
4230                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
4231
4232                 if(block == NULL)
4233                 {
4234                         // Create dummy block
4235                         block = new MapBlock(this, p, true);
4236
4237                         // Add block to sector
4238                         sector->insertBlock(block);
4239                 }
4240                 // Done.
4241                 return block;
4242         }
4243
4244         //dstream<<"Not found on disk, generating."<<std::endl;
4245         // 0ms
4246         //TimeTaker("emergeBlock() generate");
4247
4248         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
4249
4250         /*
4251                 If the block doesn't exist, generate the block.
4252         */
4253         if(does_not_exist)
4254         {
4255                 block = generateBlock(p, block, sector, changed_blocks,
4256                                 lighting_invalidated_blocks); 
4257         }
4258
4259         if(lighting_expired)
4260         {
4261                 lighting_invalidated_blocks.insert(p, block);
4262         }
4263
4264 #if 0
4265         /*
4266                 Initially update sunlight
4267         */
4268         {
4269                 core::map<v3s16, bool> light_sources;
4270                 bool black_air_left = false;
4271                 bool bottom_invalid =
4272                                 block->propagateSunlight(light_sources, true,
4273                                 &black_air_left);
4274
4275                 // If sunlight didn't reach everywhere and part of block is
4276                 // above ground, lighting has to be properly updated
4277                 //if(black_air_left && some_part_underground)
4278                 if(black_air_left)
4279                 {
4280                         lighting_invalidated_blocks[block->getPos()] = block;
4281                 }
4282
4283                 if(bottom_invalid)
4284                 {
4285                         lighting_invalidated_blocks[block->getPos()] = block;
4286                 }
4287         }
4288 #endif
4289         
4290         return block;
4291 }
4292 #endif
4293
4294 s16 ServerMap::findGroundLevel(v2s16 p2d)
4295 {
4296 #if 0
4297         /*
4298                 Uh, just do something random...
4299         */
4300         // Find existing map from top to down
4301         s16 max=63;
4302         s16 min=-64;
4303         v3s16 p(p2d.X, max, p2d.Y);
4304         for(; p.Y>min; p.Y--)
4305         {
4306                 MapNode n = getNodeNoEx(p);
4307                 if(n.d != CONTENT_IGNORE)
4308                         break;
4309         }
4310         if(p.Y == min)
4311                 goto plan_b;
4312         // If this node is not air, go to plan b
4313         if(getNodeNoEx(p).d != CONTENT_AIR)
4314                 goto plan_b;
4315         // Search existing walkable and return it
4316         for(; p.Y>min; p.Y--)
4317         {
4318                 MapNode n = getNodeNoEx(p);
4319                 if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
4320                         return p.Y;
4321         }
4322
4323         // Move to plan b
4324 plan_b:
4325 #endif
4326
4327         /*
4328                 Determine from map generator noise functions
4329         */
4330         
4331         s16 level = find_ground_level_from_noise(m_seed, p2d, 1);
4332         return level;
4333
4334         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
4335         //return (s16)level;
4336 }
4337
4338 void ServerMap::createDirs(std::string path)
4339 {
4340         if(fs::CreateAllDirs(path) == false)
4341         {
4342                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
4343                                 <<"\""<<path<<"\""<<std::endl;
4344                 throw BaseException("ServerMap failed to create directory");
4345         }
4346 }
4347
4348 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
4349 {
4350         char cc[9];
4351         switch(layout)
4352         {
4353                 case 1:
4354                         snprintf(cc, 9, "%.4x%.4x",
4355                                 (unsigned int)pos.X&0xffff,
4356                                 (unsigned int)pos.Y&0xffff);
4357
4358                         return m_savedir + "/sectors/" + cc;
4359                 case 2:
4360                         snprintf(cc, 9, "%.3x/%.3x",
4361                                 (unsigned int)pos.X&0xfff,
4362                                 (unsigned int)pos.Y&0xfff);
4363
4364                         return m_savedir + "/sectors2/" + cc;
4365                 default:
4366                         assert(false);
4367         }
4368 }
4369
4370 v2s16 ServerMap::getSectorPos(std::string dirname)
4371 {
4372         unsigned int x, y;
4373         int r;
4374         size_t spos = dirname.rfind('/') + 1;
4375         assert(spos != std::string::npos);
4376         if(dirname.size() - spos == 8)
4377         {
4378                 // Old layout
4379                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
4380         }
4381         else if(dirname.size() - spos == 3)
4382         {
4383                 // New layout
4384                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
4385                 // Sign-extend the 12 bit values up to 16 bits...
4386                 if(x&0x800) x|=0xF000;
4387                 if(y&0x800) y|=0xF000;
4388         }
4389         else
4390         {
4391                 assert(false);
4392         }
4393         assert(r == 2);
4394         v2s16 pos((s16)x, (s16)y);
4395         return pos;
4396 }
4397
4398 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
4399 {
4400         v2s16 p2d = getSectorPos(sectordir);
4401
4402         if(blockfile.size() != 4){
4403                 throw InvalidFilenameException("Invalid block filename");
4404         }
4405         unsigned int y;
4406         int r = sscanf(blockfile.c_str(), "%4x", &y);
4407         if(r != 1)
4408                 throw InvalidFilenameException("Invalid block filename");
4409         return v3s16(p2d.X, y, p2d.Y);
4410 }
4411
4412 std::string ServerMap::getBlockFilename(v3s16 p)
4413 {
4414         char cc[5];
4415         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
4416         return cc;
4417 }
4418
4419 void ServerMap::save(bool only_changed)
4420 {
4421         DSTACK(__FUNCTION_NAME);
4422         if(m_map_saving_enabled == false)
4423         {
4424                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
4425                 return;
4426         }
4427         
4428         if(only_changed == false)
4429                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
4430                                 <<std::endl;
4431         
4432         if(only_changed == false || m_map_metadata_changed)
4433         {
4434                 saveMapMeta();
4435         }
4436
4437         u32 sector_meta_count = 0;
4438         u32 block_count = 0;
4439         u32 block_count_all = 0; // Number of blocks in memory
4440         
4441         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
4442         for(; i.atEnd() == false; i++)
4443         {
4444                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
4445                 assert(sector->getId() == MAPSECTOR_SERVER);
4446         
4447                 if(sector->differs_from_disk || only_changed == false)
4448                 {
4449                         saveSectorMeta(sector);
4450                         sector_meta_count++;
4451                 }
4452                 core::list<MapBlock*> blocks;
4453                 sector->getBlocks(blocks);
4454                 core::list<MapBlock*>::Iterator j;
4455                 for(j=blocks.begin(); j!=blocks.end(); j++)
4456                 {
4457                         MapBlock *block = *j;
4458                         
4459                         block_count_all++;
4460
4461                         if(block->getModified() >= MOD_STATE_WRITE_NEEDED 
4462                                         || only_changed == false)
4463                         {
4464                                 saveBlock(block);
4465                                 block_count++;
4466
4467                                 /*dstream<<"ServerMap: Written block ("
4468                                                 <<block->getPos().X<<","
4469                                                 <<block->getPos().Y<<","
4470                                                 <<block->getPos().Z<<")"
4471                                                 <<std::endl;*/
4472                         }
4473                 }
4474         }
4475
4476         /*
4477                 Only print if something happened or saved whole map
4478         */
4479         if(only_changed == false || sector_meta_count != 0
4480                         || block_count != 0)
4481         {
4482                 dstream<<DTIME<<"ServerMap: Written: "
4483                                 <<sector_meta_count<<" sector metadata files, "
4484                                 <<block_count<<" block files"
4485                                 <<", "<<block_count_all<<" blocks in memory."
4486                                 <<std::endl;
4487         }
4488 }
4489
4490 void ServerMap::saveMapMeta()
4491 {
4492         DSTACK(__FUNCTION_NAME);
4493         
4494         dstream<<"INFO: ServerMap::saveMapMeta(): "
4495                         <<"seed="<<m_seed
4496                         <<std::endl;
4497
4498         createDirs(m_savedir);
4499         
4500         std::string fullpath = m_savedir + "/map_meta.txt";
4501         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
4502         if(os.good() == false)
4503         {
4504                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
4505                                 <<"could not open"<<fullpath<<std::endl;
4506                 throw FileNotGoodException("Cannot open chunk metadata");
4507         }
4508         
4509         Settings params;
4510         params.setU64("seed", m_seed);
4511
4512         params.writeLines(os);
4513
4514         os<<"[end_of_params]\n";
4515         
4516         m_map_metadata_changed = false;
4517 }
4518
4519 void ServerMap::loadMapMeta()
4520 {
4521         DSTACK(__FUNCTION_NAME);
4522         
4523         dstream<<"INFO: ServerMap::loadMapMeta(): Loading map metadata"
4524                         <<std::endl;
4525
4526         std::string fullpath = m_savedir + "/map_meta.txt";
4527         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4528         if(is.good() == false)
4529         {
4530                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
4531                                 <<"could not open"<<fullpath<<std::endl;
4532                 throw FileNotGoodException("Cannot open map metadata");
4533         }
4534
4535         Settings params;
4536
4537         for(;;)
4538         {
4539                 if(is.eof())
4540                         throw SerializationError
4541                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
4542                 std::string line;
4543                 std::getline(is, line);
4544                 std::string trimmedline = trim(line);
4545                 if(trimmedline == "[end_of_params]")
4546                         break;
4547                 params.parseConfigLine(line);
4548         }
4549
4550         m_seed = params.getU64("seed");
4551
4552         dstream<<"INFO: ServerMap::loadMapMeta(): "
4553                         <<"seed="<<m_seed
4554                         <<std::endl;
4555 }
4556
4557 void ServerMap::saveSectorMeta(ServerMapSector *sector)
4558 {
4559         DSTACK(__FUNCTION_NAME);
4560         // Format used for writing
4561         u8 version = SER_FMT_VER_HIGHEST;
4562         // Get destination
4563         v2s16 pos = sector->getPos();
4564         std::string dir = getSectorDir(pos);
4565         createDirs(dir);
4566         
4567         std::string fullpath = dir + "/meta";
4568         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
4569         if(o.good() == false)
4570                 throw FileNotGoodException("Cannot open sector metafile");
4571
4572         sector->serialize(o, version);
4573         
4574         sector->differs_from_disk = false;
4575 }
4576
4577 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
4578 {
4579         DSTACK(__FUNCTION_NAME);
4580         // Get destination
4581         v2s16 p2d = getSectorPos(sectordir);
4582
4583         ServerMapSector *sector = NULL;
4584
4585         std::string fullpath = sectordir + "/meta";
4586         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4587         if(is.good() == false)
4588         {
4589                 // If the directory exists anyway, it probably is in some old
4590                 // format. Just go ahead and create the sector.
4591                 if(fs::PathExists(sectordir))
4592                 {
4593                         dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
4594                                         <<fullpath<<" doesn't exist but directory does."
4595                                         <<" Continuing with a sector with no metadata."
4596                                         <<std::endl;
4597                         sector = new ServerMapSector(this, p2d);
4598                         m_sectors.insert(p2d, sector);
4599                 }
4600                 else
4601                 {
4602                         throw FileNotGoodException("Cannot open sector metafile");
4603                 }
4604         }
4605         else
4606         {
4607                 sector = ServerMapSector::deSerialize
4608                                 (is, this, p2d, m_sectors);
4609                 if(save_after_load)
4610                         saveSectorMeta(sector);
4611         }
4612         
4613         sector->differs_from_disk = false;
4614
4615         return sector;
4616 }
4617
4618 bool ServerMap::loadSectorMeta(v2s16 p2d)
4619 {
4620         DSTACK(__FUNCTION_NAME);
4621
4622         MapSector *sector = NULL;
4623
4624         // The directory layout we're going to load from.
4625         //  1 - original sectors/xxxxzzzz/
4626         //  2 - new sectors2/xxx/zzz/
4627         //  If we load from anything but the latest structure, we will
4628         //  immediately save to the new one, and remove the old.
4629         int loadlayout = 1;
4630         std::string sectordir1 = getSectorDir(p2d, 1);
4631         std::string sectordir;
4632         if(fs::PathExists(sectordir1))
4633         {
4634                 sectordir = sectordir1;
4635         }
4636         else
4637         {
4638                 loadlayout = 2;
4639                 sectordir = getSectorDir(p2d, 2);
4640         }
4641
4642         try{
4643                 sector = loadSectorMeta(sectordir, loadlayout != 2);
4644         }
4645         catch(InvalidFilenameException &e)
4646         {
4647                 return false;
4648         }
4649         catch(FileNotGoodException &e)
4650         {
4651                 return false;
4652         }
4653         catch(std::exception &e)
4654         {
4655                 return false;
4656         }
4657         
4658         return true;
4659 }
4660
4661 #if 0
4662 bool ServerMap::loadSectorFull(v2s16 p2d)
4663 {
4664         DSTACK(__FUNCTION_NAME);
4665
4666         MapSector *sector = NULL;
4667
4668         // The directory layout we're going to load from.
4669         //  1 - original sectors/xxxxzzzz/
4670         //  2 - new sectors2/xxx/zzz/
4671         //  If we load from anything but the latest structure, we will
4672         //  immediately save to the new one, and remove the old.
4673         int loadlayout = 1;
4674         std::string sectordir1 = getSectorDir(p2d, 1);
4675         std::string sectordir;
4676         if(fs::PathExists(sectordir1))
4677         {
4678                 sectordir = sectordir1;
4679         }
4680         else
4681         {
4682                 loadlayout = 2;
4683                 sectordir = getSectorDir(p2d, 2);
4684         }
4685
4686         try{
4687                 sector = loadSectorMeta(sectordir, loadlayout != 2);
4688         }
4689         catch(InvalidFilenameException &e)
4690         {
4691                 return false;
4692         }
4693         catch(FileNotGoodException &e)
4694         {
4695                 return false;
4696         }
4697         catch(std::exception &e)
4698         {
4699                 return false;
4700         }
4701         
4702         /*
4703                 Load blocks
4704         */
4705         std::vector<fs::DirListNode> list2 = fs::GetDirListing
4706                         (sectordir);
4707         std::vector<fs::DirListNode>::iterator i2;
4708         for(i2=list2.begin(); i2!=list2.end(); i2++)
4709         {
4710                 // We want files
4711                 if(i2->dir)
4712                         continue;
4713                 try{
4714                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
4715                 }
4716                 catch(InvalidFilenameException &e)
4717                 {
4718                         // This catches unknown crap in directory
4719                 }
4720         }
4721
4722         if(loadlayout != 2)
4723         {
4724                 dstream<<"Sector converted to new layout - deleting "<<
4725                         sectordir1<<std::endl;
4726                 fs::RecursiveDelete(sectordir1);
4727         }
4728
4729         return true;
4730 }
4731 #endif
4732
4733 void ServerMap::saveBlock(MapBlock *block)
4734 {
4735         DSTACK(__FUNCTION_NAME);
4736         /*
4737                 Dummy blocks are not written
4738         */
4739         if(block->isDummy())
4740         {
4741                 /*v3s16 p = block->getPos();
4742                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
4743                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
4744                 return;
4745         }
4746
4747         // Format used for writing
4748         u8 version = SER_FMT_VER_HIGHEST;
4749         // Get destination
4750         v3s16 p3d = block->getPos();
4751         
4752         v2s16 p2d(p3d.X, p3d.Z);
4753         std::string sectordir = getSectorDir(p2d);
4754
4755         createDirs(sectordir);
4756
4757         std::string fullpath = sectordir+"/"+getBlockFilename(p3d);
4758         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
4759         if(o.good() == false)
4760                 throw FileNotGoodException("Cannot open block data");
4761
4762         /*
4763                 [0] u8 serialization version
4764                 [1] data
4765         */
4766         o.write((char*)&version, 1);
4767         
4768         // Write basic data
4769         block->serialize(o, version);
4770         
4771         // Write extra data stored on disk
4772         block->serializeDiskExtra(o, version);
4773
4774         // We just wrote it to the disk so clear modified flag
4775         block->resetModified();
4776 }
4777
4778 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
4779 {
4780         DSTACK(__FUNCTION_NAME);
4781
4782         std::string fullpath = sectordir+"/"+blockfile;
4783         try{
4784
4785                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4786                 if(is.good() == false)
4787                         throw FileNotGoodException("Cannot open block file");
4788                 
4789                 v3s16 p3d = getBlockPos(sectordir, blockfile);
4790                 v2s16 p2d(p3d.X, p3d.Z);
4791                 
4792                 assert(sector->getPos() == p2d);
4793                 
4794                 u8 version = SER_FMT_VER_INVALID;
4795                 is.read((char*)&version, 1);
4796
4797                 if(is.fail())
4798                         throw SerializationError("ServerMap::loadBlock(): Failed"
4799                                         " to read MapBlock version");
4800
4801                 /*u32 block_size = MapBlock::serializedLength(version);
4802                 SharedBuffer<u8> data(block_size);
4803                 is.read((char*)*data, block_size);*/
4804
4805                 // This will always return a sector because we're the server
4806                 //MapSector *sector = emergeSector(p2d);
4807
4808                 MapBlock *block = NULL;
4809                 bool created_new = false;
4810                 try{
4811                         block = sector->getBlockNoCreate(p3d.Y);
4812                 }
4813                 catch(InvalidPositionException &e)
4814                 {
4815                         block = sector->createBlankBlockNoInsert(p3d.Y);
4816                         created_new = true;
4817                 }
4818                 
4819                 // Read basic data
4820                 block->deSerialize(is, version);
4821
4822                 // Read extra data stored on disk
4823                 block->deSerializeDiskExtra(is, version);
4824                 
4825                 // If it's a new block, insert it to the map
4826                 if(created_new)
4827                         sector->insertBlock(block);
4828                 
4829                 /*
4830                         Save blocks loaded in old format in new format
4831                 */
4832
4833                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
4834                 {
4835                         saveBlock(block);
4836                 }
4837                 
4838                 // We just loaded it from the disk, so it's up-to-date.
4839                 block->resetModified();
4840
4841         }
4842         catch(SerializationError &e)
4843         {
4844                 dstream<<"WARNING: Invalid block data on disk "
4845                                 <<"fullpath="<<fullpath
4846                                 <<" (SerializationError). "
4847                                 <<"what()="<<e.what()
4848                                 <<std::endl;
4849                                 //" Ignoring. A new one will be generated.
4850                 assert(0);
4851
4852                 // TODO: Backup file; name is in fullpath.
4853         }
4854 }
4855
4856 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
4857 {
4858         DSTACK(__FUNCTION_NAME);
4859
4860         v2s16 p2d(blockpos.X, blockpos.Z);
4861
4862         // The directory layout we're going to load from.
4863         //  1 - original sectors/xxxxzzzz/
4864         //  2 - new sectors2/xxx/zzz/
4865         //  If we load from anything but the latest structure, we will
4866         //  immediately save to the new one, and remove the old.
4867         int loadlayout = 1;
4868         std::string sectordir1 = getSectorDir(p2d, 1);
4869         std::string sectordir;
4870         if(fs::PathExists(sectordir1))
4871         {
4872                 sectordir = sectordir1;
4873         }
4874         else
4875         {
4876                 loadlayout = 2;
4877                 sectordir = getSectorDir(p2d, 2);
4878         }
4879         
4880         /*
4881                 Make sure sector is loaded
4882         */
4883         MapSector *sector = getSectorNoGenerateNoEx(p2d);
4884         if(sector == NULL)
4885         {
4886                 try{
4887                         sector = loadSectorMeta(sectordir, loadlayout != 2);
4888                 }
4889                 catch(InvalidFilenameException &e)
4890                 {
4891                         return false;
4892                 }
4893                 catch(FileNotGoodException &e)
4894                 {
4895                         return false;
4896                 }
4897                 catch(std::exception &e)
4898                 {
4899                         return false;
4900                 }
4901         }
4902         
4903         /*
4904                 Make sure file exists
4905         */
4906
4907         std::string blockfilename = getBlockFilename(blockpos);
4908         if(fs::PathExists(sectordir+"/"+blockfilename) == false)
4909                 return NULL;
4910
4911         /*
4912                 Load block
4913         */
4914         loadBlock(sectordir, blockfilename, sector, loadlayout != 2);
4915         return getBlockNoCreateNoEx(blockpos);
4916 }
4917
4918 void ServerMap::PrintInfo(std::ostream &out)
4919 {
4920         out<<"ServerMap: ";
4921 }
4922
4923 #ifndef SERVER
4924
4925 /*
4926         ClientMap
4927 */
4928
4929 ClientMap::ClientMap(
4930                 Client *client,
4931                 MapDrawControl &control,
4932                 scene::ISceneNode* parent,
4933                 scene::ISceneManager* mgr,
4934                 s32 id
4935 ):
4936         Map(dout_client),
4937         scene::ISceneNode(parent, mgr, id),
4938         m_client(client),
4939         m_control(control),
4940         m_camera_position(0,0,0),
4941         m_camera_direction(0,0,1)
4942 {
4943         m_camera_mutex.Init();
4944         assert(m_camera_mutex.IsInitialized());
4945         
4946         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
4947                         BS*1000000,BS*1000000,BS*1000000);
4948 }
4949
4950 ClientMap::~ClientMap()
4951 {
4952         /*JMutexAutoLock lock(mesh_mutex);
4953         
4954         if(mesh != NULL)
4955         {
4956                 mesh->drop();
4957                 mesh = NULL;
4958         }*/
4959 }
4960
4961 MapSector * ClientMap::emergeSector(v2s16 p2d)
4962 {
4963         DSTACK(__FUNCTION_NAME);
4964         // Check that it doesn't exist already
4965         try{
4966                 return getSectorNoGenerate(p2d);
4967         }
4968         catch(InvalidPositionException &e)
4969         {
4970         }
4971         
4972         // Create a sector
4973         ClientMapSector *sector = new ClientMapSector(this, p2d);
4974         
4975         {
4976                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
4977                 m_sectors.insert(p2d, sector);
4978         }
4979         
4980         return sector;
4981 }
4982
4983 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
4984 {
4985         DSTACK(__FUNCTION_NAME);
4986         ClientMapSector *sector = NULL;
4987
4988         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
4989         
4990         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
4991
4992         if(n != NULL)
4993         {
4994                 sector = (ClientMapSector*)n->getValue();
4995                 assert(sector->getId() == MAPSECTOR_CLIENT);
4996         }
4997         else
4998         {
4999                 sector = new ClientMapSector(this, p2d);
5000                 {
5001                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
5002                         m_sectors.insert(p2d, sector);
5003                 }
5004         }
5005
5006         sector->deSerialize(is);
5007 }
5008
5009 void ClientMap::OnRegisterSceneNode()
5010 {
5011         if(IsVisible)
5012         {
5013                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
5014                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
5015         }
5016
5017         ISceneNode::OnRegisterSceneNode();
5018 }
5019
5020 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
5021 {
5022         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
5023         DSTACK(__FUNCTION_NAME);
5024
5025         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
5026         
5027         /*
5028                 This is called two times per frame, reset on the non-transparent one
5029         */
5030         if(pass == scene::ESNRP_SOLID)
5031         {
5032                 m_last_drawn_sectors.clear();
5033         }
5034
5035         /*
5036                 Get time for measuring timeout.
5037                 
5038                 Measuring time is very useful for long delays when the
5039                 machine is swapping a lot.
5040         */
5041         int time1 = time(0);
5042
5043         //u32 daynight_ratio = m_client->getDayNightRatio();
5044
5045         m_camera_mutex.Lock();
5046         v3f camera_position = m_camera_position;
5047         v3f camera_direction = m_camera_direction;
5048         m_camera_mutex.Unlock();
5049
5050         /*
5051                 Get all blocks and draw all visible ones
5052         */
5053
5054         v3s16 cam_pos_nodes(
5055                         camera_position.X / BS,
5056                         camera_position.Y / BS,
5057                         camera_position.Z / BS);
5058
5059         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
5060
5061         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
5062         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
5063
5064         // Take a fair amount as we will be dropping more out later
5065         v3s16 p_blocks_min(
5066                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
5067                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
5068                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
5069         v3s16 p_blocks_max(
5070                         p_nodes_max.X / MAP_BLOCKSIZE,
5071                         p_nodes_max.Y / MAP_BLOCKSIZE,
5072                         p_nodes_max.Z / MAP_BLOCKSIZE);
5073         
5074         u32 vertex_count = 0;
5075         
5076         // For limiting number of mesh updates per frame
5077         u32 mesh_update_count = 0;
5078         
5079         u32 blocks_would_have_drawn = 0;
5080         u32 blocks_drawn = 0;
5081
5082         int timecheck_counter = 0;
5083         core::map<v2s16, MapSector*>::Iterator si;
5084         si = m_sectors.getIterator();
5085         for(; si.atEnd() == false; si++)
5086         {
5087                 {
5088                         timecheck_counter++;
5089                         if(timecheck_counter > 50)
5090                         {
5091                                 timecheck_counter = 0;
5092                                 int time2 = time(0);
5093                                 if(time2 > time1 + 4)
5094                                 {
5095                                         dstream<<"ClientMap::renderMap(): "
5096                                                 "Rendering takes ages, returning."
5097                                                 <<std::endl;
5098                                         return;
5099                                 }
5100                         }
5101                 }
5102
5103                 MapSector *sector = si.getNode()->getValue();
5104                 v2s16 sp = sector->getPos();
5105                 
5106                 if(m_control.range_all == false)
5107                 {
5108                         if(sp.X < p_blocks_min.X
5109                         || sp.X > p_blocks_max.X
5110                         || sp.Y < p_blocks_min.Z
5111                         || sp.Y > p_blocks_max.Z)
5112                                 continue;
5113                 }
5114
5115                 core::list< MapBlock * > sectorblocks;
5116                 sector->getBlocks(sectorblocks);
5117                 
5118                 /*
5119                         Draw blocks
5120                 */
5121                 
5122                 u32 sector_blocks_drawn = 0;
5123
5124                 core::list< MapBlock * >::Iterator i;
5125                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5126                 {
5127                         MapBlock *block = *i;
5128
5129                         /*
5130                                 Compare block position to camera position, skip
5131                                 if not seen on display
5132                         */
5133                         
5134                         float range = 100000 * BS;
5135                         if(m_control.range_all == false)
5136                                 range = m_control.wanted_range * BS;
5137                         
5138                         float d = 0.0;
5139                         if(isBlockInSight(block->getPos(), camera_position,
5140                                         camera_direction, range, &d) == false)
5141                         {
5142                                 continue;
5143                         }
5144                         
5145                         // This is ugly (spherical distance limit?)
5146                         /*if(m_control.range_all == false &&
5147                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
5148                                 continue;*/
5149
5150 #if 1
5151                         /*
5152                                 Update expired mesh (used for day/night change)
5153
5154                                 It doesn't work exactly like it should now with the
5155                                 tasked mesh update but whatever.
5156                         */
5157
5158                         bool mesh_expired = false;
5159                         
5160                         {
5161                                 JMutexAutoLock lock(block->mesh_mutex);
5162
5163                                 mesh_expired = block->getMeshExpired();
5164
5165                                 // Mesh has not been expired and there is no mesh:
5166                                 // block has no content
5167                                 if(block->mesh == NULL && mesh_expired == false)
5168                                         continue;
5169                         }
5170
5171                         f32 faraway = BS*50;
5172                         //f32 faraway = m_control.wanted_range * BS;
5173                         
5174                         /*
5175                                 This has to be done with the mesh_mutex unlocked
5176                         */
5177                         // Pretty random but this should work somewhat nicely
5178                         if(mesh_expired && (
5179                                         (mesh_update_count < 3
5180                                                 && (d < faraway || mesh_update_count < 2)
5181                                         )
5182                                         || 
5183                                         (m_control.range_all && mesh_update_count < 20)
5184                                 )
5185                         )
5186                         /*if(mesh_expired && mesh_update_count < 6
5187                                         && (d < faraway || mesh_update_count < 3))*/
5188                         {
5189                                 mesh_update_count++;
5190
5191                                 // Mesh has been expired: generate new mesh
5192                                 //block->updateMesh(daynight_ratio);
5193                                 m_client->addUpdateMeshTask(block->getPos());
5194
5195                                 mesh_expired = false;
5196                         }
5197                         
5198 #endif
5199                         /*
5200                                 Draw the faces of the block
5201                         */
5202                         {
5203                                 JMutexAutoLock lock(block->mesh_mutex);
5204
5205                                 scene::SMesh *mesh = block->mesh;
5206
5207                                 if(mesh == NULL)
5208                                         continue;
5209                                 
5210                                 blocks_would_have_drawn++;
5211                                 if(blocks_drawn >= m_control.wanted_max_blocks
5212                                                 && m_control.range_all == false
5213                                                 && d > m_control.wanted_min_range * BS)
5214                                         continue;
5215
5216                                 blocks_drawn++;
5217                                 sector_blocks_drawn++;
5218
5219                                 u32 c = mesh->getMeshBufferCount();
5220
5221                                 for(u32 i=0; i<c; i++)
5222                                 {
5223                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
5224                                         const video::SMaterial& material = buf->getMaterial();
5225                                         video::IMaterialRenderer* rnd =
5226                                                         driver->getMaterialRenderer(material.MaterialType);
5227                                         bool transparent = (rnd && rnd->isTransparent());
5228                                         // Render transparent on transparent pass and likewise.
5229                                         if(transparent == is_transparent_pass)
5230                                         {
5231                                                 /*
5232                                                         This *shouldn't* hurt too much because Irrlicht
5233                                                         doesn't change opengl textures if the old
5234                                                         material is set again.
5235                                                 */
5236                                                 driver->setMaterial(buf->getMaterial());
5237                                                 driver->drawMeshBuffer(buf);
5238                                                 vertex_count += buf->getVertexCount();
5239                                         }
5240                                 }
5241                         }
5242                 } // foreach sectorblocks
5243
5244                 if(sector_blocks_drawn != 0)
5245                 {
5246                         m_last_drawn_sectors[sp] = true;
5247                 }
5248         }
5249         
5250         m_control.blocks_drawn = blocks_drawn;
5251         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
5252
5253         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
5254                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
5255 }
5256
5257 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
5258                 core::map<v3s16, MapBlock*> *affected_blocks)
5259 {
5260         bool changed = false;
5261         /*
5262                 Add it to all blocks touching it
5263         */
5264         v3s16 dirs[7] = {
5265                 v3s16(0,0,0), // this
5266                 v3s16(0,0,1), // back
5267                 v3s16(0,1,0), // top
5268                 v3s16(1,0,0), // right
5269                 v3s16(0,0,-1), // front
5270                 v3s16(0,-1,0), // bottom
5271                 v3s16(-1,0,0), // left
5272         };
5273         for(u16 i=0; i<7; i++)
5274         {
5275                 v3s16 p2 = p + dirs[i];
5276                 // Block position of neighbor (or requested) node
5277                 v3s16 blockpos = getNodeBlockPos(p2);
5278                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5279                 if(blockref == NULL)
5280                         continue;
5281                 // Relative position of requested node
5282                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5283                 if(blockref->setTempMod(relpos, mod))
5284                 {
5285                         changed = true;
5286                 }
5287         }
5288         if(changed && affected_blocks!=NULL)
5289         {
5290                 for(u16 i=0; i<7; i++)
5291                 {
5292                         v3s16 p2 = p + dirs[i];
5293                         // Block position of neighbor (or requested) node
5294                         v3s16 blockpos = getNodeBlockPos(p2);
5295                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5296                         if(blockref == NULL)
5297                                 continue;
5298                         affected_blocks->insert(blockpos, blockref);
5299                 }
5300         }
5301         return changed;
5302 }
5303
5304 bool ClientMap::clearTempMod(v3s16 p,
5305                 core::map<v3s16, MapBlock*> *affected_blocks)
5306 {
5307         bool changed = false;
5308         v3s16 dirs[7] = {
5309                 v3s16(0,0,0), // this
5310                 v3s16(0,0,1), // back
5311                 v3s16(0,1,0), // top
5312                 v3s16(1,0,0), // right
5313                 v3s16(0,0,-1), // front
5314                 v3s16(0,-1,0), // bottom
5315                 v3s16(-1,0,0), // left
5316         };
5317         for(u16 i=0; i<7; i++)
5318         {
5319                 v3s16 p2 = p + dirs[i];
5320                 // Block position of neighbor (or requested) node
5321                 v3s16 blockpos = getNodeBlockPos(p2);
5322                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5323                 if(blockref == NULL)
5324                         continue;
5325                 // Relative position of requested node
5326                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5327                 if(blockref->clearTempMod(relpos))
5328                 {
5329                         changed = true;
5330                 }
5331         }
5332         if(changed && affected_blocks!=NULL)
5333         {
5334                 for(u16 i=0; i<7; i++)
5335                 {
5336                         v3s16 p2 = p + dirs[i];
5337                         // Block position of neighbor (or requested) node
5338                         v3s16 blockpos = getNodeBlockPos(p2);
5339                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5340                         if(blockref == NULL)
5341                                 continue;
5342                         affected_blocks->insert(blockpos, blockref);
5343                 }
5344         }
5345         return changed;
5346 }
5347
5348 void ClientMap::expireMeshes(bool only_daynight_diffed)
5349 {
5350         TimeTaker timer("expireMeshes()");
5351
5352         core::map<v2s16, MapSector*>::Iterator si;
5353         si = m_sectors.getIterator();
5354         for(; si.atEnd() == false; si++)
5355         {
5356                 MapSector *sector = si.getNode()->getValue();
5357
5358                 core::list< MapBlock * > sectorblocks;
5359                 sector->getBlocks(sectorblocks);
5360                 
5361                 core::list< MapBlock * >::Iterator i;
5362                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5363                 {
5364                         MapBlock *block = *i;
5365
5366                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
5367                         {
5368                                 continue;
5369                         }
5370                         
5371                         {
5372                                 JMutexAutoLock lock(block->mesh_mutex);
5373                                 if(block->mesh != NULL)
5374                                 {
5375                                         /*block->mesh->drop();
5376                                         block->mesh = NULL;*/
5377                                         block->setMeshExpired(true);
5378                                 }
5379                         }
5380                 }
5381         }
5382 }
5383
5384 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
5385 {
5386         assert(mapType() == MAPTYPE_CLIENT);
5387
5388         try{
5389                 v3s16 p = blockpos + v3s16(0,0,0);
5390                 MapBlock *b = getBlockNoCreate(p);
5391                 b->updateMesh(daynight_ratio);
5392                 //b->setMeshExpired(true);
5393         }
5394         catch(InvalidPositionException &e){}
5395         // Leading edge
5396         try{
5397                 v3s16 p = blockpos + v3s16(-1,0,0);
5398                 MapBlock *b = getBlockNoCreate(p);
5399                 b->updateMesh(daynight_ratio);
5400                 //b->setMeshExpired(true);
5401         }
5402         catch(InvalidPositionException &e){}
5403         try{
5404                 v3s16 p = blockpos + v3s16(0,-1,0);
5405                 MapBlock *b = getBlockNoCreate(p);
5406                 b->updateMesh(daynight_ratio);
5407                 //b->setMeshExpired(true);
5408         }
5409         catch(InvalidPositionException &e){}
5410         try{
5411                 v3s16 p = blockpos + v3s16(0,0,-1);
5412                 MapBlock *b = getBlockNoCreate(p);
5413                 b->updateMesh(daynight_ratio);
5414                 //b->setMeshExpired(true);
5415         }
5416         catch(InvalidPositionException &e){}
5417 }
5418
5419 #if 0
5420 /*
5421         Update mesh of block in which the node is, and if the node is at the
5422         leading edge, update the appropriate leading blocks too.
5423 */
5424 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
5425 {
5426         v3s16 dirs[4] = {
5427                 v3s16(0,0,0),
5428                 v3s16(-1,0,0),
5429                 v3s16(0,-1,0),
5430                 v3s16(0,0,-1),
5431         };
5432         v3s16 blockposes[4];
5433         for(u32 i=0; i<4; i++)
5434         {
5435                 v3s16 np = nodepos + dirs[i];
5436                 blockposes[i] = getNodeBlockPos(np);
5437                 // Don't update mesh of block if it has been done already
5438                 bool already_updated = false;
5439                 for(u32 j=0; j<i; j++)
5440                 {
5441                         if(blockposes[j] == blockposes[i])
5442                         {
5443                                 already_updated = true;
5444                                 break;
5445                         }
5446                 }
5447                 if(already_updated)
5448                         continue;
5449                 // Update mesh
5450                 MapBlock *b = getBlockNoCreate(blockposes[i]);
5451                 b->updateMesh(daynight_ratio);
5452         }
5453 }
5454 #endif
5455
5456 void ClientMap::PrintInfo(std::ostream &out)
5457 {
5458         out<<"ClientMap: ";
5459 }
5460
5461 #endif // !SERVER
5462
5463 /*
5464         MapVoxelManipulator
5465 */
5466
5467 MapVoxelManipulator::MapVoxelManipulator(Map *map)
5468 {
5469         m_map = map;
5470 }
5471
5472 MapVoxelManipulator::~MapVoxelManipulator()
5473 {
5474         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
5475                         <<std::endl;*/
5476 }
5477
5478 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
5479 {
5480         TimeTaker timer1("emerge", &emerge_time);
5481
5482         // Units of these are MapBlocks
5483         v3s16 p_min = getNodeBlockPos(a.MinEdge);
5484         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
5485
5486         VoxelArea block_area_nodes
5487                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5488
5489         addArea(block_area_nodes);
5490
5491         for(s32 z=p_min.Z; z<=p_max.Z; z++)
5492         for(s32 y=p_min.Y; y<=p_max.Y; y++)
5493         for(s32 x=p_min.X; x<=p_max.X; x++)
5494         {
5495                 v3s16 p(x,y,z);
5496                 core::map<v3s16, bool>::Node *n;
5497                 n = m_loaded_blocks.find(p);
5498                 if(n != NULL)
5499                         continue;
5500                 
5501                 bool block_data_inexistent = false;
5502                 try
5503                 {
5504                         TimeTaker timer1("emerge load", &emerge_load_time);
5505
5506                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
5507                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
5508                                         <<" wanted area: ";
5509                         a.print(dstream);
5510                         dstream<<std::endl;*/
5511                         
5512                         MapBlock *block = m_map->getBlockNoCreate(p);
5513                         if(block->isDummy())
5514                                 block_data_inexistent = true;
5515                         else
5516                                 block->copyTo(*this);
5517                 }
5518                 catch(InvalidPositionException &e)
5519                 {
5520                         block_data_inexistent = true;
5521                 }
5522
5523                 if(block_data_inexistent)
5524                 {
5525                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5526                         // Fill with VOXELFLAG_INEXISTENT
5527                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
5528                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
5529                         {
5530                                 s32 i = m_area.index(a.MinEdge.X,y,z);
5531                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
5532                         }
5533                 }
5534
5535                 m_loaded_blocks.insert(p, !block_data_inexistent);
5536         }
5537
5538         //dstream<<"emerge done"<<std::endl;
5539 }
5540
5541 /*
5542         SUGG: Add an option to only update eg. water and air nodes.
5543               This will make it interfere less with important stuff if
5544                   run on background.
5545 */
5546 void MapVoxelManipulator::blitBack
5547                 (core::map<v3s16, MapBlock*> & modified_blocks)
5548 {
5549         if(m_area.getExtent() == v3s16(0,0,0))
5550                 return;
5551         
5552         //TimeTaker timer1("blitBack");
5553
5554         /*dstream<<"blitBack(): m_loaded_blocks.size()="
5555                         <<m_loaded_blocks.size()<<std::endl;*/
5556         
5557         /*
5558                 Initialize block cache
5559         */
5560         v3s16 blockpos_last;
5561         MapBlock *block = NULL;
5562         bool block_checked_in_modified = false;
5563
5564         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
5565         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
5566         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
5567         {
5568                 v3s16 p(x,y,z);
5569
5570                 u8 f = m_flags[m_area.index(p)];
5571                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
5572                         continue;
5573
5574                 MapNode &n = m_data[m_area.index(p)];
5575                         
5576                 v3s16 blockpos = getNodeBlockPos(p);
5577                 
5578                 try
5579                 {
5580                         // Get block
5581                         if(block == NULL || blockpos != blockpos_last){
5582                                 block = m_map->getBlockNoCreate(blockpos);
5583                                 blockpos_last = blockpos;
5584                                 block_checked_in_modified = false;
5585                         }
5586                         
5587                         // Calculate relative position in block
5588                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
5589
5590                         // Don't continue if nothing has changed here
5591                         if(block->getNode(relpos) == n)
5592                                 continue;
5593
5594                         //m_map->setNode(m_area.MinEdge + p, n);
5595                         block->setNode(relpos, n);
5596                         
5597                         /*
5598                                 Make sure block is in modified_blocks
5599                         */
5600                         if(block_checked_in_modified == false)
5601                         {
5602                                 modified_blocks[blockpos] = block;
5603                                 block_checked_in_modified = true;
5604                         }
5605                 }
5606                 catch(InvalidPositionException &e)
5607                 {
5608                 }
5609         }
5610 }
5611
5612 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
5613                 MapVoxelManipulator(map),
5614                 m_create_area(false)
5615 {
5616 }
5617
5618 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
5619 {
5620 }
5621
5622 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
5623 {
5624         // Just create the area so that it can be pointed to
5625         VoxelManipulator::emerge(a, caller_id);
5626 }
5627
5628 void ManualMapVoxelManipulator::initialEmerge(
5629                 v3s16 blockpos_min, v3s16 blockpos_max)
5630 {
5631         TimeTaker timer1("initialEmerge", &emerge_time);
5632
5633         // Units of these are MapBlocks
5634         v3s16 p_min = blockpos_min;
5635         v3s16 p_max = blockpos_max;
5636
5637         VoxelArea block_area_nodes
5638                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5639         
5640         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
5641         if(size_MB >= 1)
5642         {
5643                 dstream<<"initialEmerge: area: ";
5644                 block_area_nodes.print(dstream);
5645                 dstream<<" ("<<size_MB<<"MB)";
5646                 dstream<<std::endl;
5647         }
5648
5649         addArea(block_area_nodes);
5650
5651         for(s32 z=p_min.Z; z<=p_max.Z; z++)
5652         for(s32 y=p_min.Y; y<=p_max.Y; y++)
5653         for(s32 x=p_min.X; x<=p_max.X; x++)
5654         {
5655                 v3s16 p(x,y,z);
5656                 core::map<v3s16, bool>::Node *n;
5657                 n = m_loaded_blocks.find(p);
5658                 if(n != NULL)
5659                         continue;
5660                 
5661                 bool block_data_inexistent = false;
5662                 try
5663                 {
5664                         TimeTaker timer1("emerge load", &emerge_load_time);
5665
5666                         MapBlock *block = m_map->getBlockNoCreate(p);
5667                         if(block->isDummy())
5668                                 block_data_inexistent = true;
5669                         else
5670                                 block->copyTo(*this);
5671                 }
5672                 catch(InvalidPositionException &e)
5673                 {
5674                         block_data_inexistent = true;
5675                 }
5676
5677                 if(block_data_inexistent)
5678                 {
5679                         /*
5680                                 Mark area inexistent
5681                         */
5682                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5683                         // Fill with VOXELFLAG_INEXISTENT
5684                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
5685                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
5686                         {
5687                                 s32 i = m_area.index(a.MinEdge.X,y,z);
5688                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
5689                         }
5690                 }
5691
5692                 m_loaded_blocks.insert(p, !block_data_inexistent);
5693         }
5694 }
5695
5696 void ManualMapVoxelManipulator::blitBackAll(
5697                 core::map<v3s16, MapBlock*> * modified_blocks)
5698 {
5699         if(m_area.getExtent() == v3s16(0,0,0))
5700                 return;
5701         
5702         /*
5703                 Copy data of all blocks
5704         */
5705         for(core::map<v3s16, bool>::Iterator
5706                         i = m_loaded_blocks.getIterator();
5707                         i.atEnd() == false; i++)
5708         {
5709                 bool existed = i.getNode()->getValue();
5710                 if(existed == false)
5711                         continue;
5712                 v3s16 p = i.getNode()->getKey();
5713                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
5714                 if(block == NULL)
5715                 {
5716                         dstream<<"WARNING: "<<__FUNCTION_NAME
5717                                         <<": got NULL block "
5718                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
5719                                         <<std::endl;
5720                         continue;
5721                 }
5722
5723                 block->copyFrom(*this);
5724
5725                 if(modified_blocks)
5726                         modified_blocks->insert(p, block);
5727         }
5728 }
5729
5730 //END