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