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