]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
new object system
[dragonfireclient.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 #define VMANIP_FLAG_DUNGEON VOXELFLAG_CHECKED1
2113
2114 /*
2115         This is the main map generation method
2116 */
2117
2118 MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos,
2119                 core::map<v3s16, MapBlock*> &changed_blocks,
2120                 bool force)
2121 {
2122         DSTACK(__FUNCTION_NAME);
2123
2124         /*
2125                 Don't generate if already fully generated
2126         */
2127         if(force == false)
2128         {
2129                 MapChunk *chunk = getChunk(chunkpos);
2130                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
2131                 {
2132                         dstream<<"generateChunkRaw(): Chunk "
2133                                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2134                                         <<" already generated"<<std::endl;
2135                         return chunk;
2136                 }
2137         }
2138
2139         dstream<<"generateChunkRaw(): Generating chunk "
2140                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2141                         <<std::endl;
2142         
2143         TimeTaker timer("generateChunkRaw()");
2144         
2145         // The distance how far into the neighbors the generator is allowed to go.
2146         s16 max_spread_amount_sectors = 2;
2147         assert(max_spread_amount_sectors <= m_chunksize);
2148         s16 max_spread_amount = max_spread_amount_sectors * MAP_BLOCKSIZE;
2149
2150         // Minimum amount of space left on sides for mud to fall in
2151         //s16 min_mud_fall_space = 2;
2152         
2153         // Maximum diameter of stone obstacles in X and Z
2154         /*s16 stone_obstacle_max_size = (max_spread_amount-min_mud_fall_space)*2;
2155         assert(stone_obstacle_max_size/2 <= max_spread_amount-min_mud_fall_space);*/
2156         
2157         s16 y_blocks_min = -4;
2158         s16 y_blocks_max = 3;
2159         s16 h_blocks = y_blocks_max - y_blocks_min + 1;
2160         s16 y_nodes_min = y_blocks_min * MAP_BLOCKSIZE;
2161         s16 y_nodes_max = y_blocks_max * MAP_BLOCKSIZE + MAP_BLOCKSIZE - 1;
2162
2163         v2s16 sectorpos_base = chunk_to_sector(chunkpos);
2164         s16 sectorpos_base_size = m_chunksize;
2165
2166         /*v2s16 sectorpos_bigbase = chunk_to_sector(chunkpos - v2s16(1,1));
2167         s16 sectorpos_bigbase_size = m_chunksize * 3;*/
2168         v2s16 sectorpos_bigbase =
2169                         sectorpos_base - v2s16(1,1) * max_spread_amount_sectors;
2170         s16 sectorpos_bigbase_size =
2171                         sectorpos_base_size + 2 * max_spread_amount_sectors;
2172
2173         v3s16 bigarea_blocks_min(
2174                 sectorpos_bigbase.X,
2175                 y_blocks_min,
2176                 sectorpos_bigbase.Y
2177         );
2178
2179         v3s16 bigarea_blocks_max(
2180                 sectorpos_bigbase.X + sectorpos_bigbase_size - 1,
2181                 y_blocks_max,
2182                 sectorpos_bigbase.Y + sectorpos_bigbase_size - 1
2183         );
2184         
2185         // Relative values to control amount of stuff in one chunk
2186         /*u32 relative_area = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2187                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE;*/
2188         u32 relative_volume = (u32)sectorpos_base_size*MAP_BLOCKSIZE
2189                         *(u32)sectorpos_base_size*MAP_BLOCKSIZE
2190                         *(u32)h_blocks*MAP_BLOCKSIZE;
2191                 
2192         /*
2193                 The limiting edges of the lighting update, inclusive.
2194         */
2195         s16 lighting_min_d = 0-max_spread_amount;
2196         s16 lighting_max_d = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
2197
2198         /*
2199                 Create the whole area of this and the neighboring chunks
2200         */
2201         {
2202                 TimeTaker timer("generateChunkRaw() create area");
2203                 
2204                 for(s16 x=0; x<sectorpos_bigbase_size; x++)
2205                 for(s16 z=0; z<sectorpos_bigbase_size; z++)
2206                 {
2207                         v2s16 sectorpos = sectorpos_bigbase + v2s16(x,z);
2208                         ServerMapSector *sector = createSector(sectorpos);
2209                         assert(sector);
2210
2211                         for(s16 y=y_blocks_min; y<=y_blocks_max; y++)
2212                         {
2213                                 v3s16 blockpos(sectorpos.X, y, sectorpos.Y);
2214                                 MapBlock *block = createBlock(blockpos);
2215
2216                                 // Lighting won't be calculated
2217                                 //block->setLightingExpired(true);
2218                                 // Lighting will be calculated
2219                                 block->setLightingExpired(false);
2220
2221                                 /*
2222                                         Block gets sunlight if this is true.
2223
2224                                         This should be set to true when the top side of a block
2225                                         is completely exposed to the sky.
2226
2227                                         Actually this doesn't matter now because the
2228                                         initial lighting is done here.
2229                                 */
2230                                 block->setIsUnderground(y != y_blocks_max);
2231                         }
2232                 }
2233         }
2234         
2235         /*
2236                 Now we have a big empty area.
2237
2238                 Make a ManualMapVoxelManipulator that contains this and the
2239                 neighboring chunks
2240         */
2241
2242         ManualMapVoxelManipulator vmanip(this);
2243         // Add the area we just generated
2244         {
2245                 TimeTaker timer("generateChunkRaw() initialEmerge");
2246                 vmanip.initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2247         }
2248
2249         // Clear all flags
2250         vmanip.clearFlag(0xff);
2251
2252         TimeTaker timer_generate("generateChunkRaw() generate");
2253
2254         // Maximum height of the stone surface and obstacles.
2255         // This is used to disable cave generation from going too high.
2256         s16 stone_surface_max_y = 0;
2257
2258         /*
2259                 Generate general ground level to full area
2260         */
2261         
2262         {
2263         // 22ms @cs=8
2264         //TimeTaker timer1("ground level");
2265
2266         for(s16 x=0; x<sectorpos_bigbase_size*MAP_BLOCKSIZE; x++)
2267         for(s16 z=0; z<sectorpos_bigbase_size*MAP_BLOCKSIZE; z++)
2268         {
2269                 // Node position
2270                 v2s16 p2d = sectorpos_bigbase*MAP_BLOCKSIZE + v2s16(x,z);
2271                 
2272                 /*
2273                         Skip of already generated
2274                 */
2275                 {
2276                         v3s16 p(p2d.X, y_nodes_min, p2d.Y);
2277                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
2278                                 continue;
2279                 }
2280
2281                 // Ground height at this point
2282                 float surface_y_f = 0.0;
2283
2284                 // Use perlin noise for ground height
2285                 surface_y_f = base_rock_level_2d(m_seed, p2d);
2286                 
2287                 /*// Experimental stuff
2288                 {
2289                         float a = highlands_level_2d(m_seed, p2d);
2290                         if(a > surface_y_f)
2291                                 surface_y_f = a;
2292                 }*/
2293
2294                 // Convert to integer
2295                 s16 surface_y = (s16)surface_y_f;
2296                 
2297                 // Log it
2298                 if(surface_y > stone_surface_max_y)
2299                         stone_surface_max_y = surface_y;
2300
2301                 /*
2302                         Fill ground with stone
2303                 */
2304                 {
2305                         // Use fast index incrementing
2306                         v3s16 em = vmanip.m_area.getExtent();
2307                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_min, p2d.Y));
2308                         for(s16 y=y_nodes_min; y<surface_y && y<=y_nodes_max; y++)
2309                         {
2310                                 vmanip.m_data[i].d = CONTENT_STONE;
2311
2312                                 vmanip.m_area.add_y(em, i, 1);
2313                         }
2314                 }
2315         }
2316         
2317         }//timer1
2318
2319         /*
2320                 Randomize some parameters
2321         */
2322         
2323         //s32 stone_obstacle_count = 0;
2324         /*s32 stone_obstacle_count =
2325                         rangelim((1.0+noise2d(m_seed+897,
2326                         sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2327         
2328         //s16 stone_obstacle_max_height = 0;
2329         /*s16 stone_obstacle_max_height =
2330                         rangelim((1.0+noise2d(m_seed+5902,
2331                         sectorpos_base.X, sectorpos_base.Y))/2.0 * 30, 0, 100000);*/
2332
2333         /*
2334                 Loop this part, it will make stuff look older and newer nicely
2335         */
2336         //for(u32 i_age=0; i_age<1; i_age++)
2337         for(u32 i_age=0; i_age<2; i_age++)
2338         { // Aging loop
2339         /******************************
2340                 BEGINNING OF AGING LOOP
2341         ******************************/
2342
2343 #if 0
2344         {
2345         // 8ms @cs=8
2346         //TimeTaker timer1("stone obstacles");
2347
2348         /*
2349                 Add some random stone obstacles
2350         */
2351         
2352         for(s32 ri=0; ri<stone_obstacle_count; ri++)
2353         {
2354                 // Randomize max height so usually stuff will be quite low
2355                 s16 maxheight_randomized = myrand_range(0, stone_obstacle_max_height);
2356
2357                 //s16 stone_obstacle_max_size = sectorpos_base_size * MAP_BLOCKSIZE - 10;
2358                 s16 stone_obstacle_max_size = MAP_BLOCKSIZE*4-4;
2359
2360                 v3s16 ob_size(
2361                         myrand_range(5, stone_obstacle_max_size),
2362                         myrand_range(0, maxheight_randomized),
2363                         myrand_range(5, stone_obstacle_max_size)
2364                 );
2365                 
2366                 // Don't make stupid small rectangle bumps
2367                 if(ob_size.Y < 5)
2368                         continue;
2369                 
2370                 v2s16 ob_place(
2371                         myrand_range(1+ob_size.X/2+2,
2372                                         sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.X/2-2),
2373                         myrand_range(1+ob_size.Z/2+2,
2374                                         sectorpos_base_size*MAP_BLOCKSIZE-1-1-ob_size.Z/2-2)
2375                 );
2376                 
2377                 // Minimum space left on top of the obstacle
2378                 s16 min_head_space = 12;
2379                 
2380                 for(s16 x=-ob_size.X/2; x<ob_size.X/2; x++)
2381                 for(s16 z=-ob_size.Z/2; z<ob_size.Z/2; z++)
2382                 {
2383                         // Node position in 2d
2384                         v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + ob_place + v2s16(x,z);
2385                         
2386                         // Find stone ground level
2387                         // (ignore everything else than mud in already generated chunks)
2388                         // and mud amount over the stone level
2389                         s16 surface_y = 0;
2390                         s16 mud_amount = 0;
2391                         {
2392                                 v3s16 em = vmanip.m_area.getExtent();
2393                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2394                                 s16 y;
2395                                 // Go to ground level
2396                                 for(y=y_nodes_max; y>=y_nodes_min; y--)
2397                                 {
2398                                         MapNode *n = &vmanip.m_data[i];
2399                                         /*if(content_walkable(n.d)
2400                                                         && n.d != CONTENT_MUD
2401                                                         && n.d != CONTENT_GRASS)
2402                                                 break;*/
2403                                         if(n->d == CONTENT_STONE)
2404                                                 break;
2405                                         
2406                                         if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
2407                                         {
2408                                                 mud_amount++;
2409                                                 /*
2410                                                         Change to mud because otherwise we might
2411                                                         be throwing mud on grass at the next
2412                                                         step
2413                                                 */
2414                                                 n->d = CONTENT_MUD;
2415                                         }
2416                                                 
2417                                         vmanip.m_area.add_y(em, i, -1);
2418                                 }
2419                                 if(y >= y_nodes_min)
2420                                         surface_y = y;
2421                                 else
2422                                         surface_y = y_nodes_min;
2423                         }
2424
2425
2426                         /*
2427                                 Add stone on ground
2428                         */
2429                         {
2430                                 v3s16 em = vmanip.m_area.getExtent();
2431                                 s16 y_start = surface_y+1;
2432                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2433                                 s16 y;
2434                                 // Add stone
2435                                 s16 count = 0;
2436                                 for(y=y_start; y<=y_nodes_max - min_head_space; y++)
2437                                 {
2438                                         MapNode &n = vmanip.m_data[i];
2439                                         n.d = CONTENT_STONE;
2440
2441                                         if(y > stone_surface_max_y)
2442                                                 stone_surface_max_y = y;
2443
2444                                         count++;
2445                                         if(count >= ob_size.Y)
2446                                                 break;
2447                                                 
2448                                         vmanip.m_area.add_y(em, i, 1);
2449                                 }
2450                                 // Add mud
2451                                 count = 0;
2452                                 for(; y<=y_nodes_max - min_head_space; y++)
2453                                 {
2454                                         MapNode &n = vmanip.m_data[i];
2455                                         n.d = CONTENT_MUD;
2456                                         count++;
2457                                         if(count >= mud_amount)
2458                                                 break;
2459                                                 
2460                                         vmanip.m_area.add_y(em, i, 1);
2461                                 }
2462                         }
2463
2464                 }
2465         }
2466
2467         }//timer1
2468 #endif
2469
2470         {
2471         // 24ms @cs=8
2472         //TimeTaker timer1("caves");
2473
2474         /*
2475                 Make caves
2476         */
2477         u32 caves_count = relative_volume / 400000;
2478         u32 bruises_count = relative_volume * stone_surface_max_y / 40000000;
2479         if(stone_surface_max_y < WATER_LEVEL)
2480                 bruises_count = 0;
2481         /*u32 caves_count = 0;
2482         u32 bruises_count = 0;*/
2483         for(u32 jj=0; jj<caves_count+bruises_count; jj++)
2484         {
2485                 s16 min_tunnel_diameter = 3;
2486                 s16 max_tunnel_diameter = 5;
2487                 u16 tunnel_routepoints = 20;
2488                 
2489                 v3f main_direction(0,0,0);
2490
2491                 bool bruise_surface = (jj > caves_count);
2492
2493                 if(bruise_surface)
2494                 {
2495                         min_tunnel_diameter = 5;
2496                         max_tunnel_diameter = myrand_range(10, 20);
2497                         /*min_tunnel_diameter = MYMAX(0, stone_surface_max_y/6);
2498                         max_tunnel_diameter = myrand_range(MYMAX(0, stone_surface_max_y/6), MYMAX(0, stone_surface_max_y/2));*/
2499                         
2500                         /*s16 tunnel_rou = rangelim(25*(0.5+1.0*noise2d(m_seed+42,
2501                                         sectorpos_base.X, sectorpos_base.Y)), 0, 15);*/
2502
2503                         tunnel_routepoints = 5;
2504                 }
2505                 else
2506                 {
2507                 }
2508
2509                 // Allowed route area size in nodes
2510                 v3s16 ar(
2511                         sectorpos_base_size*MAP_BLOCKSIZE,
2512                         h_blocks*MAP_BLOCKSIZE,
2513                         sectorpos_base_size*MAP_BLOCKSIZE
2514                 );
2515
2516                 // Area starting point in nodes
2517                 v3s16 of(
2518                         sectorpos_base.X*MAP_BLOCKSIZE,
2519                         y_blocks_min*MAP_BLOCKSIZE,
2520                         sectorpos_base.Y*MAP_BLOCKSIZE
2521                 );
2522
2523                 // Allow a bit more
2524                 //(this should be more than the maximum radius of the tunnel)
2525                 //s16 insure = 5; // Didn't work with max_d = 20
2526                 s16 insure = 10;
2527                 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
2528                 ar += v3s16(1,0,1) * more * 2;
2529                 of -= v3s16(1,0,1) * more;
2530                 
2531                 s16 route_y_min = 0;
2532                 // Allow half a diameter + 7 over stone surface
2533                 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
2534
2535                 /*// If caves, don't go through surface too often
2536                 if(bruise_surface == false)
2537                         route_y_max -= myrand_range(0, max_tunnel_diameter*2);*/
2538
2539                 // Limit maximum to area
2540                 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
2541
2542                 if(bruise_surface)
2543                 {
2544                         /*// Minimum is at y=0
2545                         route_y_min = -of.Y - 0;*/
2546                         // Minimum is at y=max_tunnel_diameter/4
2547                         //route_y_min = -of.Y + max_tunnel_diameter/4;
2548                         //s16 min = -of.Y + max_tunnel_diameter/4;
2549                         s16 min = -of.Y + 0;
2550                         route_y_min = myrand_range(min, min + max_tunnel_diameter);
2551                         route_y_min = rangelim(route_y_min, 0, route_y_max);
2552                 }
2553
2554                 /*dstream<<"route_y_min = "<<route_y_min
2555                                 <<", route_y_max = "<<route_y_max<<std::endl;*/
2556
2557                 s16 route_start_y_min = route_y_min;
2558                 s16 route_start_y_max = route_y_max;
2559
2560                 // Start every 2nd cave from surface
2561                 bool coming_from_surface = (jj % 2 == 0 && bruise_surface == false);
2562
2563                 if(coming_from_surface)
2564                 {
2565                         route_start_y_min = -of.Y + stone_surface_max_y + 10;
2566                 }
2567                 
2568                 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
2569                 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
2570
2571                 // Randomize starting position
2572                 v3f orp(
2573                         (float)(myrand()%ar.X)+0.5,
2574                         (float)(myrand_range(route_start_y_min, route_start_y_max))+0.5,
2575                         (float)(myrand()%ar.Z)+0.5
2576                 );
2577
2578                 MapNode airnode(CONTENT_AIR);
2579                 
2580                 /*
2581                         Generate some tunnel starting from orp
2582                 */
2583                 
2584                 for(u16 j=0; j<tunnel_routepoints; j++)
2585                 {
2586                         if(j%7==0 && bruise_surface == false)
2587                         {
2588                                 main_direction = v3f(
2589                                         ((float)(myrand()%20)-(float)10)/10,
2590                                         ((float)(myrand()%20)-(float)10)/30,
2591                                         ((float)(myrand()%20)-(float)10)/10
2592                                 );
2593                                 main_direction *= (float)myrand_range(1, 3);
2594                         }
2595
2596                         // Randomize size
2597                         s16 min_d = min_tunnel_diameter;
2598                         s16 max_d = max_tunnel_diameter;
2599                         s16 rs = myrand_range(min_d, max_d);
2600                         
2601                         v3s16 maxlen;
2602                         if(bruise_surface)
2603                         {
2604                                 maxlen = v3s16(rs*7,rs*7,rs*7);
2605                         }
2606                         else
2607                         {
2608                                 maxlen = v3s16(rs*4, myrand_range(1, rs*3), rs*4);
2609                         }
2610
2611                         v3f vec;
2612                         
2613                         if(coming_from_surface && j < 3)
2614                         {
2615                                 vec = v3f(
2616                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2617                                         (float)(myrand()%(maxlen.Y*1))-(float)maxlen.Y,
2618                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2619                                 );
2620                         }
2621                         else
2622                         {
2623                                 vec = v3f(
2624                                         (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2625                                         (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
2626                                         (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2627                                 );
2628                         }
2629                         
2630                         vec += main_direction;
2631
2632                         v3f rp = orp + vec;
2633                         if(rp.X < 0)
2634                                 rp.X = 0;
2635                         else if(rp.X >= ar.X)
2636                                 rp.X = ar.X-1;
2637                         if(rp.Y < route_y_min)
2638                                 rp.Y = route_y_min;
2639                         else if(rp.Y >= route_y_max)
2640                                 rp.Y = route_y_max-1;
2641                         if(rp.Z < 0)
2642                                 rp.Z = 0;
2643                         else if(rp.Z >= ar.Z)
2644                                 rp.Z = ar.Z-1;
2645                         vec = rp - orp;
2646
2647                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
2648                         {
2649                                 v3f fp = orp + vec * f;
2650                                 v3s16 cp(fp.X, fp.Y, fp.Z);
2651
2652                                 s16 d0 = -rs/2;
2653                                 s16 d1 = d0 + rs - 1;
2654                                 for(s16 z0=d0; z0<=d1; z0++)
2655                                 {
2656                                         //s16 si = rs - MYMAX(0, abs(z0)-rs/4);
2657                                         s16 si = rs - MYMAX(0, abs(z0)-rs/7);
2658                                         for(s16 x0=-si; x0<=si-1; x0++)
2659                                         {
2660                                                 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
2661                                                 //s16 si2 = rs - MYMAX(0, maxabsxz-rs/4);
2662                                                 s16 si2 = rs - MYMAX(0, maxabsxz-rs/7);
2663                                                 //s16 si2 = rs - abs(x0);
2664                                                 for(s16 y0=-si2+1+2; y0<=si2-1; y0++)
2665                                                 {
2666                                                         s16 z = cp.Z + z0;
2667                                                         s16 y = cp.Y + y0;
2668                                                         s16 x = cp.X + x0;
2669                                                         v3s16 p(x,y,z);
2670                                                         /*if(isInArea(p, ar) == false)
2671                                                                 continue;*/
2672                                                         // Check only height
2673                                                         if(y < 0 || y >= ar.Y)
2674                                                                 continue;
2675                                                         p += of;
2676                                                         
2677                                                         //assert(vmanip.m_area.contains(p));
2678                                                         if(vmanip.m_area.contains(p) == false)
2679                                                         {
2680                                                                 dstream<<"WARNING: "<<__FUNCTION_NAME
2681                                                                                 <<":"<<__LINE__<<": "
2682                                                                                 <<"point not in area"
2683                                                                                 <<std::endl;
2684                                                                 continue;
2685                                                         }
2686                                                         
2687                                                         // Just set it to air, it will be changed to
2688                                                         // water afterwards
2689                                                         u32 i = vmanip.m_area.index(p);
2690                                                         vmanip.m_data[i] = airnode;
2691
2692                                                         if(bruise_surface == false)
2693                                                         {
2694                                                                 // Set tunnel flag
2695                                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON;
2696                                                         }
2697                                                 }
2698                                         }
2699                                 }
2700                         }
2701
2702                         orp = rp;
2703                 }
2704         
2705         }
2706
2707         }//timer1
2708         {
2709         // 46ms @cs=8
2710         //TimeTaker timer1("ore veins");
2711
2712         /*
2713                 Make ore veins
2714         */
2715         for(u32 jj=0; jj<relative_volume/1000; jj++)
2716         {
2717                 s16 max_vein_diameter = 3;
2718
2719                 // Allowed route area size in nodes
2720                 v3s16 ar(
2721                         sectorpos_base_size*MAP_BLOCKSIZE,
2722                         h_blocks*MAP_BLOCKSIZE,
2723                         sectorpos_base_size*MAP_BLOCKSIZE
2724                 );
2725
2726                 // Area starting point in nodes
2727                 v3s16 of(
2728                         sectorpos_base.X*MAP_BLOCKSIZE,
2729                         y_blocks_min*MAP_BLOCKSIZE,
2730                         sectorpos_base.Y*MAP_BLOCKSIZE
2731                 );
2732
2733                 // Allow a bit more
2734                 //(this should be more than the maximum radius of the tunnel)
2735                 s16 insure = 3;
2736                 s16 more = max_spread_amount - max_vein_diameter/2 - insure;
2737                 ar += v3s16(1,0,1) * more * 2;
2738                 of -= v3s16(1,0,1) * more;
2739                 
2740                 // Randomize starting position
2741                 v3f orp(
2742                         (float)(myrand()%ar.X)+0.5,
2743                         (float)(myrand()%ar.Y)+0.5,
2744                         (float)(myrand()%ar.Z)+0.5
2745                 );
2746
2747                 // Randomize mineral
2748                 u8 mineral;
2749                 if(myrand()%3 != 0)
2750                         mineral = MINERAL_COAL;
2751                 else
2752                         mineral = MINERAL_IRON;
2753
2754                 /*
2755                         Generate some vein starting from orp
2756                 */
2757
2758                 for(u16 j=0; j<2; j++)
2759                 {
2760                         /*v3f rp(
2761                                 (float)(myrand()%ar.X)+0.5,
2762                                 (float)(myrand()%ar.Y)+0.5,
2763                                 (float)(myrand()%ar.Z)+0.5
2764                         );
2765                         v3f vec = rp - orp;*/
2766                         
2767                         v3s16 maxlen(5, 5, 5);
2768                         v3f vec(
2769                                 (float)(myrand()%(maxlen.X*2))-(float)maxlen.X,
2770                                 (float)(myrand()%(maxlen.Y*2))-(float)maxlen.Y,
2771                                 (float)(myrand()%(maxlen.Z*2))-(float)maxlen.Z
2772                         );
2773                         v3f rp = orp + vec;
2774                         if(rp.X < 0)
2775                                 rp.X = 0;
2776                         else if(rp.X >= ar.X)
2777                                 rp.X = ar.X;
2778                         if(rp.Y < 0)
2779                                 rp.Y = 0;
2780                         else if(rp.Y >= ar.Y)
2781                                 rp.Y = ar.Y;
2782                         if(rp.Z < 0)
2783                                 rp.Z = 0;
2784                         else if(rp.Z >= ar.Z)
2785                                 rp.Z = ar.Z;
2786                         vec = rp - orp;
2787
2788                         // Randomize size
2789                         s16 min_d = 0;
2790                         s16 max_d = max_vein_diameter;
2791                         s16 rs = myrand_range(min_d, max_d);
2792                         
2793                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
2794                         {
2795                                 v3f fp = orp + vec * f;
2796                                 v3s16 cp(fp.X, fp.Y, fp.Z);
2797                                 s16 d0 = -rs/2;
2798                                 s16 d1 = d0 + rs - 1;
2799                                 for(s16 z0=d0; z0<=d1; z0++)
2800                                 {
2801                                         s16 si = rs - abs(z0);
2802                                         for(s16 x0=-si; x0<=si-1; x0++)
2803                                         {
2804                                                 s16 si2 = rs - abs(x0);
2805                                                 for(s16 y0=-si2+1; y0<=si2-1; y0++)
2806                                                 {
2807                                                         // Don't put mineral to every place
2808                                                         if(myrand()%5 != 0)
2809                                                                 continue;
2810
2811                                                         s16 z = cp.Z + z0;
2812                                                         s16 y = cp.Y + y0;
2813                                                         s16 x = cp.X + x0;
2814                                                         v3s16 p(x,y,z);
2815                                                         /*if(isInArea(p, ar) == false)
2816                                                                 continue;*/
2817                                                         // Check only height
2818                                                         if(y < 0 || y >= ar.Y)
2819                                                                 continue;
2820                                                         p += of;
2821                                                         
2822                                                         assert(vmanip.m_area.contains(p));
2823                                                         
2824                                                         // Just set it to air, it will be changed to
2825                                                         // water afterwards
2826                                                         u32 i = vmanip.m_area.index(p);
2827                                                         MapNode *n = &vmanip.m_data[i];
2828                                                         if(n->d == CONTENT_STONE)
2829                                                                 n->param = mineral;
2830                                                 }
2831                                         }
2832                                 }
2833                         }
2834
2835                         orp = rp;
2836                 }
2837         
2838         }
2839
2840         }//timer1
2841         {
2842         // 15ms @cs=8
2843         //TimeTaker timer1("add mud");
2844
2845         /*
2846                 Add mud to the central chunk
2847         */
2848         
2849         for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
2850         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)
2851         {
2852                 // Node position in 2d
2853                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
2854                 
2855                 // Randomize mud amount
2856                 s16 mud_add_amount = (s16)(2.5 + 2.0 * noise2d_perlin(
2857                                 0.5+(float)p2d.X/200, 0.5+(float)p2d.Y/200,
2858                                 m_seed+1, 3, 0.55));
2859
2860                 // Find ground level
2861                 s16 surface_y = find_ground_level_clever(vmanip, p2d);
2862
2863                 /*
2864                         If topmost node is grass, change it to mud.
2865                         It might be if it was flown to there from a neighboring
2866                         chunk and then converted.
2867                 */
2868                 {
2869                         u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
2870                         MapNode *n = &vmanip.m_data[i];
2871                         if(n->d == CONTENT_GRASS)
2872                                 n->d = CONTENT_MUD;
2873                 }
2874
2875                 /*
2876                         Add mud on ground
2877                 */
2878                 {
2879                         s16 mudcount = 0;
2880                         v3s16 em = vmanip.m_area.getExtent();
2881                         s16 y_start = surface_y+1;
2882                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2883                         for(s16 y=y_start; y<=y_nodes_max; y++)
2884                         {
2885                                 if(mudcount >= mud_add_amount)
2886                                         break;
2887                                         
2888                                 MapNode &n = vmanip.m_data[i];
2889                                 n.d = CONTENT_MUD;
2890                                 mudcount++;
2891
2892                                 vmanip.m_area.add_y(em, i, 1);
2893                         }
2894                 }
2895
2896         }
2897
2898         }//timer1
2899         {
2900         // 340ms @cs=8
2901         TimeTaker timer1("flow mud");
2902
2903         /*
2904                 Flow mud away from steep edges
2905         */
2906
2907         // Limit area by 1 because mud is flown into neighbors.
2908         s16 mudflow_minpos = 0-max_spread_amount+1;
2909         s16 mudflow_maxpos = sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-2;
2910
2911         // Iterate a few times
2912         for(s16 k=0; k<3; k++)
2913         {
2914
2915         for(s16 x=mudflow_minpos;
2916                         x<=mudflow_maxpos;
2917                         x++)
2918         for(s16 z=mudflow_minpos;
2919                         z<=mudflow_maxpos;
2920                         z++)
2921         {
2922                 // Invert coordinates every 2nd iteration
2923                 if(k%2 == 0)
2924                 {
2925                         x = mudflow_maxpos - (x-mudflow_minpos);
2926                         z = mudflow_maxpos - (z-mudflow_minpos);
2927                 }
2928
2929                 // Node position in 2d
2930                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
2931                 
2932                 v3s16 em = vmanip.m_area.getExtent();
2933                 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
2934                 s16 y=y_nodes_max;
2935
2936                 for(;; y--)
2937                 {
2938                         MapNode *n = NULL;
2939                         // Find mud
2940                         for(; y>=y_nodes_min; y--)
2941                         {
2942                                 n = &vmanip.m_data[i];
2943                                 //if(content_walkable(n->d))
2944                                 //      break;
2945                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
2946                                         break;
2947                                         
2948                                 vmanip.m_area.add_y(em, i, -1);
2949                         }
2950
2951                         // Stop if out of area
2952                         //if(vmanip.m_area.contains(i) == false)
2953                         if(y < y_nodes_min)
2954                                 break;
2955
2956                         /*// If not mud, do nothing to it
2957                         MapNode *n = &vmanip.m_data[i];
2958                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2959                                 continue;*/
2960
2961                         /*
2962                                 Don't flow it if the stuff under it is not mud
2963                         */
2964                         {
2965                                 u32 i2 = i;
2966                                 vmanip.m_area.add_y(em, i2, -1);
2967                                 // Cancel if out of area
2968                                 if(vmanip.m_area.contains(i2) == false)
2969                                         continue;
2970                                 MapNode *n2 = &vmanip.m_data[i2];
2971                                 if(n2->d != CONTENT_MUD && n2->d != CONTENT_GRASS)
2972                                         continue;
2973                         }
2974
2975                         // Make it exactly mud
2976                         n->d = CONTENT_MUD;
2977                         
2978                         /*s16 recurse_count = 0;
2979         mudflow_recurse:*/
2980
2981                         v3s16 dirs4[4] = {
2982                                 v3s16(0,0,1), // back
2983                                 v3s16(1,0,0), // right
2984                                 v3s16(0,0,-1), // front
2985                                 v3s16(-1,0,0), // left
2986                         };
2987
2988                         // Theck that upper is air or doesn't exist.
2989                         // Cancel dropping if upper keeps it in place
2990                         u32 i3 = i;
2991                         vmanip.m_area.add_y(em, i3, 1);
2992                         if(vmanip.m_area.contains(i3) == true
2993                                         && content_walkable(vmanip.m_data[i3].d) == true)
2994                         {
2995                                 continue;
2996                         }
2997
2998                         // Drop mud on side
2999                         
3000                         for(u32 di=0; di<4; di++)
3001                         {
3002                                 v3s16 dirp = dirs4[di];
3003                                 u32 i2 = i;
3004                                 // Move to side
3005                                 vmanip.m_area.add_p(em, i2, dirp);
3006                                 // Fail if out of area
3007                                 if(vmanip.m_area.contains(i2) == false)
3008                                         continue;
3009                                 // Check that side is air
3010                                 MapNode *n2 = &vmanip.m_data[i2];
3011                                 if(content_walkable(n2->d))
3012                                         continue;
3013                                 // Check that under side is air
3014                                 vmanip.m_area.add_y(em, i2, -1);
3015                                 if(vmanip.m_area.contains(i2) == false)
3016                                         continue;
3017                                 n2 = &vmanip.m_data[i2];
3018                                 if(content_walkable(n2->d))
3019                                         continue;
3020                                 /*// Check that under that is air (need a drop of 2)
3021                                 vmanip.m_area.add_y(em, i2, -1);
3022                                 if(vmanip.m_area.contains(i2) == false)
3023                                         continue;
3024                                 n2 = &vmanip.m_data[i2];
3025                                 if(content_walkable(n2->d))
3026                                         continue;*/
3027                                 // Loop further down until not air
3028                                 do{
3029                                         vmanip.m_area.add_y(em, i2, -1);
3030                                         // Fail if out of area
3031                                         if(vmanip.m_area.contains(i2) == false)
3032                                                 continue;
3033                                         n2 = &vmanip.m_data[i2];
3034                                 }while(content_walkable(n2->d) == false);
3035                                 // Loop one up so that we're in air
3036                                 vmanip.m_area.add_y(em, i2, 1);
3037                                 n2 = &vmanip.m_data[i2];
3038
3039                                 // Move mud to new place
3040                                 *n2 = *n;
3041                                 // Set old place to be air
3042                                 *n = MapNode(CONTENT_AIR);
3043
3044                                 // Done
3045                                 break;
3046                         }
3047                 }
3048         }
3049         
3050         }
3051
3052         }//timer1
3053         {
3054         // 50ms @cs=8
3055         //TimeTaker timer1("add water");
3056
3057         /*
3058                 Add water to the central chunk (and a bit more)
3059         */
3060         
3061         for(s16 x=0-max_spread_amount;
3062                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3063                         x++)
3064         for(s16 z=0-max_spread_amount;
3065                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3066                         z++)
3067         {
3068                 // Node position in 2d
3069                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3070                 
3071                 // Find ground level
3072                 //s16 surface_y = find_ground_level(vmanip, p2d);
3073
3074                 /*
3075                         If ground level is over water level, skip.
3076                         NOTE: This leaves caves near water without water,
3077                         which looks especially crappy when the nearby water
3078                         won't start flowing either for some reason
3079                 */
3080                 /*if(surface_y > WATER_LEVEL)
3081                         continue;*/
3082
3083                 /*
3084                         Add water on ground
3085                 */
3086                 {
3087                         v3s16 em = vmanip.m_area.getExtent();
3088                         u8 light = LIGHT_MAX;
3089                         // Start at global water surface level
3090                         s16 y_start = WATER_LEVEL;
3091                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3092                         MapNode *n = &vmanip.m_data[i];
3093
3094                         /*// Add first one to transforming liquid queue, if water
3095                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
3096                         {
3097                                 v3s16 p = v3s16(p2d.X, y_start, p2d.Y);
3098                                 m_transforming_liquid.push_back(p);
3099                         }*/
3100
3101                         for(s16 y=y_start; y>=y_nodes_min; y--)
3102                         {
3103                                 n = &vmanip.m_data[i];
3104                                 
3105                                 // Stop when there is no water and no air
3106                                 if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE
3107                                                 && n->d != CONTENT_WATER)
3108                                 {
3109                                         /*// Add bottom one to transforming liquid queue
3110                                         vmanip.m_area.add_y(em, i, 1);
3111                                         n = &vmanip.m_data[i];
3112                                         if(n->d == CONTENT_WATER || n->d == CONTENT_WATERSOURCE)
3113                                         {
3114                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
3115                                                 m_transforming_liquid.push_back(p);
3116                                         }*/
3117
3118                                         break;
3119                                 }
3120                                 
3121                                 // Make water only not in caves
3122                                 if(!(vmanip.m_flags[i]&VMANIP_FLAG_DUNGEON))
3123                                 {
3124                                         n->d = CONTENT_WATERSOURCE;
3125                                         //n->setLight(LIGHTBANK_DAY, light);
3126
3127                                         // Add to transforming liquid queue (in case it'd
3128                                         // start flowing)
3129                                         v3s16 p = v3s16(p2d.X, y, p2d.Y);
3130                                         m_transforming_liquid.push_back(p);
3131                                 }
3132                                 
3133                                 // Next one
3134                                 vmanip.m_area.add_y(em, i, -1);
3135                                 if(light > 0)
3136                                         light--;
3137                         }
3138                 }
3139
3140         }
3141
3142         }//timer1
3143         
3144         } // Aging loop
3145         /***********************
3146                 END OF AGING LOOP
3147         ************************/
3148
3149         {
3150         //TimeTaker timer1("convert mud to sand");
3151
3152         /*
3153                 Convert mud to sand
3154         */
3155         
3156         //s16 mud_add_amount = myrand_range(2, 4);
3157         //s16 mud_add_amount = 0;
3158         
3159         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3160         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3161         for(s16 x=0-max_spread_amount+1;
3162                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3163                         x++)
3164         for(s16 z=0-max_spread_amount+1;
3165                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3166                         z++)
3167         {
3168                 // Node position in 2d
3169                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3170                 
3171                 // Determine whether to have sand here
3172                 double sandnoise = noise2d_perlin(
3173                                 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
3174                                 m_seed+59420, 3, 0.50);
3175
3176                 bool have_sand = (sandnoise > -0.15);
3177
3178                 if(have_sand == false)
3179                         continue;
3180
3181                 // Find ground level
3182                 s16 surface_y = find_ground_level_clever(vmanip, p2d);
3183                 
3184                 if(surface_y > WATER_LEVEL + 2)
3185                         continue;
3186
3187                 {
3188                         v3s16 em = vmanip.m_area.getExtent();
3189                         s16 y_start = surface_y;
3190                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3191                         u32 not_sand_counter = 0;
3192                         for(s16 y=y_start; y>=y_nodes_min; y--)
3193                         {
3194                                 MapNode *n = &vmanip.m_data[i];
3195                                 if(n->d == CONTENT_MUD || n->d == CONTENT_GRASS)
3196                                 {
3197                                         n->d = CONTENT_SAND;
3198                                 }
3199                                 else
3200                                 {
3201                                         not_sand_counter++;
3202                                         if(not_sand_counter > 3)
3203                                                 break;
3204                                 }
3205
3206                                 vmanip.m_area.add_y(em, i, -1);
3207                         }
3208                 }
3209
3210         }
3211
3212         }//timer1
3213         {
3214         // 1ms @cs=8
3215         //TimeTaker timer1("generate trees");
3216
3217         /*
3218                 Generate some trees
3219         */
3220         {
3221                 // Divide area into parts
3222                 s16 div = 8;
3223                 s16 sidelen = sectorpos_base_size*MAP_BLOCKSIZE / div;
3224                 double area = sidelen * sidelen;
3225                 for(s16 x0=0; x0<div; x0++)
3226                 for(s16 z0=0; z0<div; z0++)
3227                 {
3228                         // Center position of part of division
3229                         v2s16 p2d_center(
3230                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen/2 + sidelen*x0,
3231                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen/2 + sidelen*z0
3232                         );
3233                         // Minimum edge of part of division
3234                         v2s16 p2d_min(
3235                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen*x0,
3236                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen*z0
3237                         );
3238                         // Maximum edge of part of division
3239                         v2s16 p2d_max(
3240                                 sectorpos_base.X*MAP_BLOCKSIZE + sidelen + sidelen*x0 - 1,
3241                                 sectorpos_base.Y*MAP_BLOCKSIZE + sidelen + sidelen*z0 - 1
3242                         );
3243                         // Amount of trees
3244                         u32 tree_count = area * tree_amount_2d(m_seed, p2d_center);
3245                         // Put trees in random places on part of division
3246                         for(u32 i=0; i<tree_count; i++)
3247                         {
3248                                 s16 x = myrand_range(p2d_min.X, p2d_max.X);
3249                                 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
3250                                 s16 y = find_ground_level(vmanip, v2s16(x,z));
3251                                 // Don't make a tree under water level
3252                                 if(y < WATER_LEVEL)
3253                                         continue;
3254                                 // Don't make a tree so high that it doesn't fit
3255                                 if(y > y_nodes_max - 6)
3256                                         continue;
3257                                 v3s16 p(x,y,z);
3258                                 /*
3259                                         Trees grow only on mud and grass
3260                                 */
3261                                 {
3262                                         u32 i = vmanip.m_area.index(v3s16(p));
3263                                         MapNode *n = &vmanip.m_data[i];
3264                                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
3265                                                 continue;
3266                                 }
3267                                 p.Y++;
3268                                 // Make a tree
3269                                 make_tree(vmanip, p);
3270                         }
3271                 }
3272                 /*u32 tree_max = relative_area / 60;
3273                 //u32 count = myrand_range(0, tree_max);
3274                 for(u32 i=0; i<count; i++)
3275                 {
3276                         s16 x = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
3277                         s16 z = myrand_range(0, sectorpos_base_size*MAP_BLOCKSIZE-1);
3278                         x += sectorpos_base.X*MAP_BLOCKSIZE;
3279                         z += sectorpos_base.Y*MAP_BLOCKSIZE;
3280                         s16 y = find_ground_level(vmanip, v2s16(x,z));
3281                         // Don't make a tree under water level
3282                         if(y < WATER_LEVEL)
3283                                 continue;
3284                         v3s16 p(x,y+1,z);
3285                         // Make a tree
3286                         make_tree(vmanip, p);
3287                 }*/
3288         }
3289
3290         }//timer1
3291
3292         {
3293         // 19ms @cs=8
3294         //TimeTaker timer1("grow grass");
3295
3296         /*
3297                 Grow grass
3298         */
3299
3300         /*for(s16 x=0-4; x<sectorpos_base_size*MAP_BLOCKSIZE+4; x++)
3301         for(s16 z=0-4; z<sectorpos_base_size*MAP_BLOCKSIZE+4; z++)*/
3302         for(s16 x=0-max_spread_amount;
3303                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3304                         x++)
3305         for(s16 z=0-max_spread_amount;
3306                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount;
3307                         z++)
3308         {
3309                 // Node position in 2d
3310                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3311                 
3312                 /*
3313                         Find the lowest surface to which enough light ends up
3314                         to make grass grow.
3315
3316                         Basically just wait until not air and not leaves.
3317                 */
3318                 s16 surface_y = 0;
3319                 {
3320                         v3s16 em = vmanip.m_area.getExtent();
3321                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
3322                         s16 y;
3323                         // Go to ground level
3324                         for(y=y_nodes_max; y>=y_nodes_min; y--)
3325                         {
3326                                 MapNode &n = vmanip.m_data[i];
3327                                 if(n.d != CONTENT_AIR
3328                                                 && n.d != CONTENT_LEAVES)
3329                                         break;
3330                                 vmanip.m_area.add_y(em, i, -1);
3331                         }
3332                         if(y >= y_nodes_min)
3333                                 surface_y = y;
3334                         else
3335                                 surface_y = y_nodes_min;
3336                 }
3337                 
3338                 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
3339                 MapNode *n = &vmanip.m_data[i];
3340                 if(n->d == CONTENT_MUD)
3341                         n->d = CONTENT_GRASS;
3342         }
3343
3344         }//timer1
3345
3346         /*
3347                 Initial lighting (sunlight)
3348         */
3349
3350         core::map<v3s16, bool> light_sources;
3351
3352         {
3353         // 750ms @cs=8, can't optimize more
3354         TimeTaker timer1("initial lighting");
3355
3356 #if 0
3357         /*
3358                 Go through the edges and add all nodes that have light to light_sources
3359         */
3360         
3361         // Four edges
3362         for(s16 i=0; i<4; i++)
3363         // Edge length
3364         for(s16 j=lighting_min_d;
3365                         j<=lighting_max_d;
3366                         j++)
3367         {
3368                 s16 x;
3369                 s16 z;
3370                 // +-X
3371                 if(i == 0 || i == 1)
3372                 {
3373                         x = (i==0) ? lighting_min_d : lighting_max_d;
3374                         if(i == 0)
3375                                 z = lighting_min_d;
3376                         else
3377                                 z = lighting_max_d;
3378                 }
3379                 // +-Z
3380                 else
3381                 {
3382                         z = (i==0) ? lighting_min_d : lighting_max_d;
3383                         if(i == 0)
3384                                 x = lighting_min_d;
3385                         else
3386                                 x = lighting_max_d;
3387                 }
3388                 
3389                 // Node position in 2d
3390                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3391
3392                 {
3393                         v3s16 em = vmanip.m_area.getExtent();
3394                         s16 y_start = y_nodes_max;
3395                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3396                         for(s16 y=y_start; y>=y_nodes_min; y--)
3397                         {
3398                                 MapNode *n = &vmanip.m_data[i];
3399                                 if(n->getLight(LIGHTBANK_DAY) != 0)
3400                                 {
3401                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3402                                 }
3403                                 //NOTE: This is broken, at least the index has to
3404                                 // be incremented
3405                         }
3406                 }
3407         }
3408 #endif
3409
3410 #if 1
3411         /*
3412                 Go through the edges and apply sunlight to them, not caring
3413                 about neighbors
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                 // Loop from top to down
3448                 {
3449                         u8 light = LIGHT_SUN;
3450                         v3s16 em = vmanip.m_area.getExtent();
3451                         s16 y_start = y_nodes_max;
3452                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3453                         for(s16 y=y_start; y>=y_nodes_min; y--)
3454                         {
3455                                 MapNode *n = &vmanip.m_data[i];
3456                                 if(light_propagates_content(n->d) == false)
3457                                 {
3458                                         light = 0;
3459                                 }
3460                                 else if(light != LIGHT_SUN
3461                                         || sunlight_propagates_content(n->d) == false)
3462                                 {
3463                                         if(light > 0)
3464                                                 light--;
3465                                 }
3466                                 
3467                                 n->setLight(LIGHTBANK_DAY, light);
3468                                 n->setLight(LIGHTBANK_NIGHT, 0);
3469                                 
3470                                 if(light != 0)
3471                                 {
3472                                         // Insert light source
3473                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3474                                 }
3475                                 
3476                                 // Increment index by y
3477                                 vmanip.m_area.add_y(em, i, -1);
3478                         }
3479                 }
3480         }
3481 #endif
3482
3483         /*for(s16 x=0; x<sectorpos_base_size*MAP_BLOCKSIZE; x++)
3484         for(s16 z=0; z<sectorpos_base_size*MAP_BLOCKSIZE; z++)*/
3485         /*for(s16 x=0-max_spread_amount+1;
3486                         x<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3487                         x++)
3488         for(s16 z=0-max_spread_amount+1;
3489                         z<sectorpos_base_size*MAP_BLOCKSIZE+max_spread_amount-1;
3490                         z++)*/
3491 #if 1
3492         /*
3493                 This has to be 1 smaller than the actual area, because
3494                 neighboring nodes are checked.
3495         */
3496         for(s16 x=lighting_min_d+1;
3497                         x<=lighting_max_d-1;
3498                         x++)
3499         for(s16 z=lighting_min_d+1;
3500                         z<=lighting_max_d-1;
3501                         z++)
3502         {
3503                 // Node position in 2d
3504                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3505                 
3506                 /*
3507                         Apply initial sunlight
3508                 */
3509                 {
3510                         u8 light = LIGHT_SUN;
3511                         bool add_to_sources = false;
3512                         v3s16 em = vmanip.m_area.getExtent();
3513                         s16 y_start = y_nodes_max;
3514                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3515                         for(s16 y=y_start; y>=y_nodes_min; y--)
3516                         {
3517                                 MapNode *n = &vmanip.m_data[i];
3518
3519                                 if(light_propagates_content(n->d) == false)
3520                                 {
3521                                         light = 0;
3522                                 }
3523                                 else if(light != LIGHT_SUN
3524                                         || sunlight_propagates_content(n->d) == false)
3525                                 {
3526                                         if(light > 0)
3527                                                 light--;
3528                                 }
3529                                 
3530                                 // This doesn't take much time
3531                                 if(add_to_sources == false)
3532                                 {
3533                                         /*
3534                                                 Check sides. If side is not air or water, start
3535                                                 adding to light_sources.
3536                                         */
3537                                         v3s16 dirs4[4] = {
3538                                                 v3s16(0,0,1), // back
3539                                                 v3s16(1,0,0), // right
3540                                                 v3s16(0,0,-1), // front
3541                                                 v3s16(-1,0,0), // left
3542                                         };
3543                                         for(u32 di=0; di<4; di++)
3544                                         {
3545                                                 v3s16 dirp = dirs4[di];
3546                                                 u32 i2 = i;
3547                                                 vmanip.m_area.add_p(em, i2, dirp);
3548                                                 MapNode *n2 = &vmanip.m_data[i2];
3549                                                 if(
3550                                                         n2->d != CONTENT_AIR
3551                                                         && n2->d != CONTENT_WATERSOURCE
3552                                                         && n2->d != CONTENT_WATER
3553                                                 ){
3554                                                         add_to_sources = true;
3555                                                         break;
3556                                                 }
3557                                         }
3558                                 }
3559                                 
3560                                 n->setLight(LIGHTBANK_DAY, light);
3561                                 n->setLight(LIGHTBANK_NIGHT, 0);
3562                                 
3563                                 // This doesn't take much time
3564                                 if(light != 0 && add_to_sources)
3565                                 {
3566                                         // Insert light source
3567                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3568                                 }
3569                                 
3570                                 // Increment index by y
3571                                 vmanip.m_area.add_y(em, i, -1);
3572                         }
3573                 }
3574         }
3575 #endif
3576
3577 #if 0
3578         for(s16 x=lighting_min_d+1;
3579                         x<=lighting_max_d-1;
3580                         x++)
3581         for(s16 z=lighting_min_d+1;
3582                         z<=lighting_max_d-1;
3583                         z++)
3584         {
3585                 // Node position in 2d
3586                 v2s16 p2d = sectorpos_base*MAP_BLOCKSIZE + v2s16(x,z);
3587                 
3588                 /*
3589                         Apply initial sunlight
3590                 */
3591                 {
3592                         u8 light = LIGHT_SUN;
3593                         v3s16 em = vmanip.m_area.getExtent();
3594                         s16 y_start = y_nodes_max;
3595                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
3596                         for(s16 y=y_start; y>=y_nodes_min; y--)
3597                         {
3598                                 MapNode *n = &vmanip.m_data[i];
3599
3600                                 if(light_propagates_content(n->d) == false)
3601                                 {
3602                                         light = 0;
3603                                 }
3604                                 else if(light != LIGHT_SUN
3605                                         || sunlight_propagates_content(n->d) == false)
3606                                 {
3607                                         if(light > 0)
3608                                                 light--;
3609                                 }
3610                                 
3611                                 n->setLight(LIGHTBANK_DAY, light);
3612                                 n->setLight(LIGHTBANK_NIGHT, 0);
3613                                 
3614                                 // This doesn't take much time
3615                                 if(light != 0)
3616                                 {
3617                                         // Insert light source
3618                                         light_sources.insert(v3s16(p2d.X, y, p2d.Y), true);
3619                                 }
3620                                 
3621                                 // Increment index by y
3622                                 vmanip.m_area.add_y(em, i, -1);
3623                         }
3624                 }
3625         }
3626 #endif
3627
3628         }//timer1
3629
3630         // Spread light around
3631         {
3632                 TimeTaker timer("generateChunkRaw() spreadLight");
3633                 vmanip.spreadLight(LIGHTBANK_DAY, light_sources);
3634         }
3635         
3636         /*
3637                 Generation ended
3638         */
3639
3640         timer_generate.stop();
3641
3642         /*
3643                 Blit generated stuff to map
3644         */
3645         {
3646                 // 70ms @cs=8
3647                 //TimeTaker timer("generateChunkRaw() blitBackAll");
3648                 vmanip.blitBackAll(&changed_blocks);
3649         }
3650
3651         /*
3652                 Update day/night difference cache of the MapBlocks
3653         */
3654         {
3655                 for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
3656                                 i.atEnd() == false; i++)
3657                 {
3658                         MapBlock *block = i.getNode()->getValue();
3659                         block->updateDayNightDiff();
3660                 }
3661         }
3662
3663         
3664         /*
3665                 Create chunk metadata
3666         */
3667
3668         for(s16 x=-1; x<=1; x++)
3669         for(s16 y=-1; y<=1; y++)
3670         {
3671                 v2s16 chunkpos0 = chunkpos + v2s16(x,y);
3672                 // Add chunk meta information
3673                 MapChunk *chunk = getChunk(chunkpos0);
3674                 if(chunk == NULL)
3675                 {
3676                         chunk = new MapChunk();
3677                         m_chunks.insert(chunkpos0, chunk);
3678                 }
3679                 //chunk->setIsVolatile(true);
3680                 if(chunk->getGenLevel() > GENERATED_PARTLY)
3681                         chunk->setGenLevel(GENERATED_PARTLY);
3682         }
3683
3684         /*
3685                 Set central chunk non-volatile
3686         */
3687         MapChunk *chunk = getChunk(chunkpos);
3688         assert(chunk);
3689         // Set non-volatile
3690         //chunk->setIsVolatile(false);
3691         chunk->setGenLevel(GENERATED_FULLY);
3692         
3693         /*
3694                 Save changed parts of map
3695         */
3696         save(true);
3697
3698         /*
3699                 Return central chunk (which was requested)
3700         */
3701         return chunk;
3702 }
3703
3704 MapChunk* ServerMap::generateChunk(v2s16 chunkpos1,
3705                 core::map<v3s16, MapBlock*> &changed_blocks)
3706 {
3707         dstream<<"generateChunk(): Generating chunk "
3708                         <<"("<<chunkpos1.X<<","<<chunkpos1.Y<<")"
3709                         <<std::endl;
3710         
3711         /*for(s16 x=-1; x<=1; x++)
3712         for(s16 y=-1; y<=1; y++)*/
3713         for(s16 x=-0; x<=0; x++)
3714         for(s16 y=-0; y<=0; y++)
3715         {
3716                 v2s16 chunkpos0 = chunkpos1 + v2s16(x,y);
3717                 MapChunk *chunk = getChunk(chunkpos0);
3718                 // Skip if already generated
3719                 if(chunk != NULL && chunk->getGenLevel() == GENERATED_FULLY)
3720                         continue;
3721                 generateChunkRaw(chunkpos0, changed_blocks);
3722         }
3723         
3724         assert(chunkNonVolatile(chunkpos1));
3725
3726         MapChunk *chunk = getChunk(chunkpos1);
3727         return chunk;
3728 }
3729
3730 ServerMapSector * ServerMap::createSector(v2s16 p2d)
3731 {
3732         DSTACK("%s: p2d=(%d,%d)",
3733                         __FUNCTION_NAME,
3734                         p2d.X, p2d.Y);
3735         
3736         /*
3737                 Check if it exists already in memory
3738         */
3739         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3740         if(sector != NULL)
3741                 return sector;
3742         
3743         /*
3744                 Try to load it from disk (with blocks)
3745         */
3746         if(loadSectorFull(p2d) == true)
3747         {
3748                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
3749                 if(sector == NULL)
3750                 {
3751                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
3752                         throw InvalidPositionException("");
3753                 }
3754                 return sector;
3755         }
3756
3757         /*
3758                 Do not create over-limit
3759         */
3760         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3761         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3762         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3763         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
3764                 throw InvalidPositionException("createSector(): pos. over limit");
3765
3766         /*
3767                 Generate blank sector
3768         */
3769         
3770         sector = new ServerMapSector(this, p2d);
3771         
3772         // Sector position on map in nodes
3773         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
3774
3775         /*
3776                 Insert to container
3777         */
3778         m_sectors.insert(p2d, sector);
3779         
3780         return sector;
3781 }
3782
3783 MapSector * ServerMap::emergeSector(v2s16 p2d,
3784                 core::map<v3s16, MapBlock*> &changed_blocks)
3785 {
3786         DSTACK("%s: p2d=(%d,%d)",
3787                         __FUNCTION_NAME,
3788                         p2d.X, p2d.Y);
3789         
3790         /*
3791                 Check chunk status
3792         */
3793         v2s16 chunkpos = sector_to_chunk(p2d);
3794         /*bool chunk_nonvolatile = false;
3795         MapChunk *chunk = getChunk(chunkpos);
3796         if(chunk && chunk->getIsVolatile() == false)
3797                 chunk_nonvolatile = true;*/
3798         bool chunk_nonvolatile = chunkNonVolatile(chunkpos);
3799
3800         /*
3801                 If chunk is not fully generated, generate chunk
3802         */
3803         if(chunk_nonvolatile == false)
3804         {
3805                 // Generate chunk and neighbors
3806                 generateChunk(chunkpos, changed_blocks);
3807         }
3808         
3809         /*
3810                 Return sector if it exists now
3811         */
3812         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3813         if(sector != NULL)
3814                 return sector;
3815         
3816         /*
3817                 Try to load it from disk
3818         */
3819         if(loadSectorFull(p2d) == true)
3820         {
3821                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
3822                 if(sector == NULL)
3823                 {
3824                         dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"<<std::endl;
3825                         throw InvalidPositionException("");
3826                 }
3827                 return sector;
3828         }
3829
3830         /*
3831                 generateChunk should have generated the sector
3832         */
3833         //assert(0);
3834         
3835         dstream<<"WARNING: ServerMap::emergeSector: Cannot find sector ("
3836                         <<p2d.X<<","<<p2d.Y<<" and chunk is already generated. "
3837                         <<std::endl;
3838
3839 #if 0
3840         dstream<<"WARNING: Creating an empty sector."<<std::endl;
3841
3842         return createSector(p2d);
3843         
3844 #endif
3845         
3846 #if 1
3847         dstream<<"WARNING: Forcing regeneration of chunk."<<std::endl;
3848
3849         // Generate chunk
3850         generateChunkRaw(chunkpos, changed_blocks, true);
3851
3852         /*
3853                 Return sector if it exists now
3854         */
3855         sector = getSectorNoGenerateNoEx(p2d);
3856         if(sector != NULL)
3857                 return sector;
3858         
3859         dstream<<"ERROR: Could not get sector from anywhere."<<std::endl;
3860         
3861         assert(0);
3862 #endif
3863         
3864         /*
3865                 Generate directly
3866         */
3867         //return generateSector();
3868 }
3869
3870 /*
3871         NOTE: This is not used for main map generation, only for blocks
3872         that are very high or low
3873 */
3874 MapBlock * ServerMap::generateBlock(
3875                 v3s16 p,
3876                 MapBlock *original_dummy,
3877                 ServerMapSector *sector,
3878                 core::map<v3s16, MapBlock*> &changed_blocks,
3879                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
3880 )
3881 {
3882         DSTACK("%s: p=(%d,%d,%d)",
3883                         __FUNCTION_NAME,
3884                         p.X, p.Y, p.Z);
3885         
3886         /*dstream<<"generateBlock(): "
3887                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3888                         <<std::endl;*/
3889         
3890         MapBlock *block = original_dummy;
3891                         
3892         v2s16 p2d(p.X, p.Z);
3893         s16 block_y = p.Y;
3894         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
3895         
3896         /*
3897                 Do not generate over-limit
3898         */
3899         if(blockpos_over_limit(p))
3900         {
3901                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
3902                 throw InvalidPositionException("generateBlock(): pos. over limit");
3903         }
3904
3905         /*
3906                 If block doesn't exist, create one.
3907                 If it exists, it is a dummy. In that case unDummify() it.
3908
3909                 NOTE: This already sets the map as the parent of the block
3910         */
3911         if(block == NULL)
3912         {
3913                 block = sector->createBlankBlockNoInsert(block_y);
3914         }
3915         else
3916         {
3917                 // Remove the block so that nobody can get a half-generated one.
3918                 sector->removeBlock(block);
3919                 // Allocate the block to contain the generated data
3920                 block->unDummify();
3921         }
3922         
3923         u8 water_material = CONTENT_WATERSOURCE;
3924         
3925         s32 lowest_ground_y = 32767;
3926         s32 highest_ground_y = -32768;
3927         
3928         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3929         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3930         {
3931                 //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
3932
3933                 //s16 surface_y = 0;
3934
3935                 s16 surface_y = base_rock_level_2d(m_seed, p2d_nodes+v2s16(x0,z0))
3936                                 + AVERAGE_MUD_AMOUNT;
3937
3938                 if(surface_y < lowest_ground_y)
3939                         lowest_ground_y = surface_y;
3940                 if(surface_y > highest_ground_y)
3941                         highest_ground_y = surface_y;
3942
3943                 s32 surface_depth = AVERAGE_MUD_AMOUNT;
3944                 
3945                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3946                 {
3947                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
3948                         MapNode n;
3949                         /*
3950                                 Calculate lighting
3951                                 
3952                                 NOTE: If there are some man-made structures above the
3953                                 newly created block, they won't be taken into account.
3954                         */
3955                         if(real_y > surface_y)
3956                                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
3957
3958                         /*
3959                                 Calculate material
3960                         */
3961
3962                         // If node is over heightmap y, it's air or water
3963                         if(real_y > surface_y)
3964                         {
3965                                 // If under water level, it's water
3966                                 if(real_y < WATER_LEVEL)
3967                                 {
3968                                         n.d = water_material;
3969                                         n.setLight(LIGHTBANK_DAY,
3970                                                         diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
3971                                         /*
3972                                                 Add to transforming liquid queue (in case it'd
3973                                                 start flowing)
3974                                         */
3975                                         v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
3976                                         m_transforming_liquid.push_back(real_pos);
3977                                 }
3978                                 // else air
3979                                 else
3980                                         n.d = CONTENT_AIR;
3981                         }
3982                         // Else it's ground or caves (air)
3983                         else
3984                         {
3985                                 // If it's surface_depth under ground, it's stone
3986                                 if(real_y <= surface_y - surface_depth)
3987                                 {
3988                                         n.d = CONTENT_STONE;
3989                                 }
3990                                 else
3991                                 {
3992                                         // It is mud if it is under the first ground
3993                                         // level or under water
3994                                         if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
3995                                         {
3996                                                 n.d = CONTENT_MUD;
3997                                         }
3998                                         else
3999                                         {
4000                                                 n.d = CONTENT_GRASS;
4001                                         }
4002
4003                                         //n.d = CONTENT_MUD;
4004                                         
4005                                         /*// If under water level, it's mud
4006                                         if(real_y < WATER_LEVEL)
4007                                                 n.d = CONTENT_MUD;
4008                                         // Only the topmost node is grass
4009                                         else if(real_y <= surface_y - 1)
4010                                                 n.d = CONTENT_MUD;
4011                                         else
4012                                                 n.d = CONTENT_GRASS;*/
4013                                 }
4014                         }
4015
4016                         block->setNode(v3s16(x0,y0,z0), n);
4017                 }
4018         }
4019         
4020         /*
4021                 Calculate some helper variables
4022         */
4023         
4024         // Completely underground if the highest part of block is under lowest
4025         // ground height.
4026         // This has to be very sure; it's probably one too strict now but
4027         // that's just better.
4028         bool completely_underground =
4029                         block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y;
4030
4031         bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
4032
4033         bool mostly_underwater_surface = false;
4034         if(highest_ground_y < WATER_LEVEL
4035                         && some_part_underground && !completely_underground)
4036                 mostly_underwater_surface = true;
4037
4038         /*
4039                 Get local attributes
4040         */
4041
4042         //dstream<<"generateBlock(): Getting local attributes"<<std::endl;
4043
4044         float caves_amount = 0.5;
4045
4046 #if 0
4047         {
4048                 /*
4049                         NOTE: BEWARE: Too big amount of attribute points slows verything
4050                         down by a lot.
4051                         1 interpolation from 5000 points takes 2-3ms.
4052                 */
4053                 //TimeTaker timer("generateBlock() local attribute retrieval");
4054                 v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
4055                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
4056                 caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
4057         }
4058 #endif
4059
4060         //dstream<<"generateBlock(): Done"<<std::endl;
4061
4062         /*
4063                 Generate caves
4064         */
4065
4066         // Initialize temporary table
4067         const s32 ued = MAP_BLOCKSIZE;
4068         bool underground_emptiness[ued*ued*ued];
4069         for(s32 i=0; i<ued*ued*ued; i++)
4070         {
4071                 underground_emptiness[i] = 0;
4072         }
4073         
4074         // Fill table
4075 #if 1
4076         {
4077                 /*
4078                         Initialize orp and ors. Try to find if some neighboring
4079                         MapBlock has a tunnel ended in its side
4080                 */
4081
4082                 v3f orp(
4083                         (float)(myrand()%ued)+0.5,
4084                         (float)(myrand()%ued)+0.5,
4085                         (float)(myrand()%ued)+0.5
4086                 );
4087                 
4088                 bool found_existing = false;
4089
4090                 // Check z-
4091                 try
4092                 {
4093                         s16 z = -1;
4094                         for(s16 y=0; y<ued; y++)
4095                         for(s16 x=0; x<ued; x++)
4096                         {
4097                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4098                                 if(getNode(ap).d == CONTENT_AIR)
4099                                 {
4100                                         orp = v3f(x+1,y+1,0);
4101                                         found_existing = true;
4102                                         goto continue_generating;
4103                                 }
4104                         }
4105                 }
4106                 catch(InvalidPositionException &e){}
4107                 
4108                 // Check z+
4109                 try
4110                 {
4111                         s16 z = ued;
4112                         for(s16 y=0; y<ued; y++)
4113                         for(s16 x=0; x<ued; x++)
4114                         {
4115                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4116                                 if(getNode(ap).d == CONTENT_AIR)
4117                                 {
4118                                         orp = v3f(x+1,y+1,ued-1);
4119                                         found_existing = true;
4120                                         goto continue_generating;
4121                                 }
4122                         }
4123                 }
4124                 catch(InvalidPositionException &e){}
4125                 
4126                 // Check x-
4127                 try
4128                 {
4129                         s16 x = -1;
4130                         for(s16 y=0; y<ued; y++)
4131                         for(s16 z=0; z<ued; z++)
4132                         {
4133                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4134                                 if(getNode(ap).d == CONTENT_AIR)
4135                                 {
4136                                         orp = v3f(0,y+1,z+1);
4137                                         found_existing = true;
4138                                         goto continue_generating;
4139                                 }
4140                         }
4141                 }
4142                 catch(InvalidPositionException &e){}
4143                 
4144                 // Check x+
4145                 try
4146                 {
4147                         s16 x = ued;
4148                         for(s16 y=0; y<ued; y++)
4149                         for(s16 z=0; z<ued; z++)
4150                         {
4151                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4152                                 if(getNode(ap).d == CONTENT_AIR)
4153                                 {
4154                                         orp = v3f(ued-1,y+1,z+1);
4155                                         found_existing = true;
4156                                         goto continue_generating;
4157                                 }
4158                         }
4159                 }
4160                 catch(InvalidPositionException &e){}
4161
4162                 // Check y-
4163                 try
4164                 {
4165                         s16 y = -1;
4166                         for(s16 x=0; x<ued; x++)
4167                         for(s16 z=0; z<ued; z++)
4168                         {
4169                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4170                                 if(getNode(ap).d == CONTENT_AIR)
4171                                 {
4172                                         orp = v3f(x+1,0,z+1);
4173                                         found_existing = true;
4174                                         goto continue_generating;
4175                                 }
4176                         }
4177                 }
4178                 catch(InvalidPositionException &e){}
4179                 
4180                 // Check y+
4181                 try
4182                 {
4183                         s16 y = ued;
4184                         for(s16 x=0; x<ued; x++)
4185                         for(s16 z=0; z<ued; z++)
4186                         {
4187                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
4188                                 if(getNode(ap).d == CONTENT_AIR)
4189                                 {
4190                                         orp = v3f(x+1,ued-1,z+1);
4191                                         found_existing = true;
4192                                         goto continue_generating;
4193                                 }
4194                         }
4195                 }
4196                 catch(InvalidPositionException &e){}
4197
4198 continue_generating:
4199                 
4200                 /*
4201                         Choose whether to actually generate cave
4202                 */
4203                 bool do_generate_caves = true;
4204                 // Don't generate if no part is underground
4205                 if(!some_part_underground)
4206                 {
4207                         do_generate_caves = false;
4208                 }
4209                 // Don't generate if mostly underwater surface
4210                 /*else if(mostly_underwater_surface)
4211                 {
4212                         do_generate_caves = false;
4213                 }*/
4214                 // Partly underground = cave
4215                 else if(!completely_underground)
4216                 {
4217                         do_generate_caves = (rand() % 100 <= (s32)(caves_amount*100));
4218                 }
4219                 // Found existing cave underground
4220                 else if(found_existing && completely_underground)
4221                 {
4222                         do_generate_caves = (rand() % 100 <= (s32)(caves_amount*100));
4223                 }
4224                 // Underground and no caves found
4225                 else
4226                 {
4227                         do_generate_caves = (rand() % 300 <= (s32)(caves_amount*100));
4228                 }
4229
4230                 if(do_generate_caves)
4231                 {
4232                         /*
4233                                 Generate some tunnel starting from orp and ors
4234                         */
4235                         for(u16 i=0; i<3; i++)
4236                         {
4237                                 v3f rp(
4238                                         (float)(myrand()%ued)+0.5,
4239                                         (float)(myrand()%ued)+0.5,
4240                                         (float)(myrand()%ued)+0.5
4241                                 );
4242                                 s16 min_d = 0;
4243                                 s16 max_d = 4;
4244                                 s16 rs = (myrand()%(max_d-min_d+1))+min_d;
4245                                 
4246                                 v3f vec = rp - orp;
4247
4248                                 for(float f=0; f<1.0; f+=0.04)
4249                                 {
4250                                         v3f fp = orp + vec * f;
4251                                         v3s16 cp(fp.X, fp.Y, fp.Z);
4252                                         s16 d0 = -rs/2;
4253                                         s16 d1 = d0 + rs - 1;
4254                                         for(s16 z0=d0; z0<=d1; z0++)
4255                                         {
4256                                                 s16 si = rs - abs(z0);
4257                                                 for(s16 x0=-si; x0<=si-1; x0++)
4258                                                 {
4259                                                         s16 si2 = rs - abs(x0);
4260                                                         for(s16 y0=-si2+1; y0<=si2-1; y0++)
4261                                                         {
4262                                                                 s16 z = cp.Z + z0;
4263                                                                 s16 y = cp.Y + y0;
4264                                                                 s16 x = cp.X + x0;
4265                                                                 v3s16 p(x,y,z);
4266                                                                 if(isInArea(p, ued) == false)
4267                                                                         continue;
4268                                                                 underground_emptiness[ued*ued*z + ued*y + x] = 1;
4269                                                         }
4270                                                 }
4271                                         }
4272                                 }
4273
4274                                 orp = rp;
4275                         }
4276                 }
4277         }
4278 #endif
4279
4280         // Set to true if has caves.
4281         // Set when some non-air is changed to air when making caves.
4282         bool has_caves = false;
4283
4284         /*
4285                 Apply temporary cave data to block
4286         */
4287
4288         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
4289         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
4290         {
4291                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
4292                 {
4293                         MapNode n = block->getNode(v3s16(x0,y0,z0));
4294
4295                         // Create caves
4296                         if(underground_emptiness[
4297                                         ued*ued*(z0*ued/MAP_BLOCKSIZE)
4298                                         +ued*(y0*ued/MAP_BLOCKSIZE)
4299                                         +(x0*ued/MAP_BLOCKSIZE)])
4300                         {
4301                                 if(content_features(n.d).walkable/*is_ground_content(n.d)*/)
4302                                 {
4303                                         // Has now caves
4304                                         has_caves = true;
4305                                         // Set air to node
4306                                         n.d = CONTENT_AIR;
4307                                 }
4308                         }
4309
4310                         block->setNode(v3s16(x0,y0,z0), n);
4311                 }
4312         }
4313         
4314         /*
4315                 This is used for guessing whether or not the block should
4316                 receive sunlight from the top if the block above doesn't exist
4317         */
4318         block->setIsUnderground(completely_underground);
4319
4320         /*
4321                 Force lighting update if some part of block is partly
4322                 underground and has caves.
4323         */
4324         /*if(some_part_underground && !completely_underground && has_caves)
4325         {
4326                 //dstream<<"Half-ground caves"<<std::endl;
4327                 lighting_invalidated_blocks[block->getPos()] = block;
4328         }*/
4329         
4330         // DEBUG: Always update lighting
4331         //lighting_invalidated_blocks[block->getPos()] = block;
4332
4333         /*
4334                 Add some minerals
4335         */
4336
4337         if(some_part_underground)
4338         {
4339                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
4340
4341                 /*
4342                         Add meseblocks
4343                 */
4344                 for(s16 i=0; i<underground_level/4 + 1; i++)
4345                 {
4346                         if(myrand()%50 == 0)
4347                         {
4348                                 v3s16 cp(
4349                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4350                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4351                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4352                                 );
4353
4354                                 MapNode n;
4355                                 n.d = CONTENT_MESE;
4356                                 
4357                                 for(u16 i=0; i<27; i++)
4358                                 {
4359                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4360                                                 if(myrand()%8 == 0)
4361                                                         block->setNode(cp+g_27dirs[i], n);
4362                                 }
4363                         }
4364                 }
4365
4366                 /*
4367                         Add coal
4368                 */
4369                 u16 coal_amount = 30;
4370                 u16 coal_rareness = 60 / coal_amount;
4371                 if(coal_rareness == 0)
4372                         coal_rareness = 1;
4373                 if(myrand()%coal_rareness == 0)
4374                 {
4375                         u16 a = myrand() % 16;
4376                         u16 amount = coal_amount * a*a*a / 1000;
4377                         for(s16 i=0; i<amount; i++)
4378                         {
4379                                 v3s16 cp(
4380                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4381                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4382                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4383                                 );
4384
4385                                 MapNode n;
4386                                 n.d = CONTENT_STONE;
4387                                 n.param = MINERAL_COAL;
4388
4389                                 for(u16 i=0; i<27; i++)
4390                                 {
4391                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4392                                                 if(myrand()%8 == 0)
4393                                                         block->setNode(cp+g_27dirs[i], n);
4394                                 }
4395                         }
4396                 }
4397
4398                 /*
4399                         Add iron
4400                 */
4401                 //TODO: change to iron_amount or whatever
4402                 u16 iron_amount = 15;
4403                 u16 iron_rareness = 60 / iron_amount;
4404                 if(iron_rareness == 0)
4405                         iron_rareness = 1;
4406                 if(myrand()%iron_rareness == 0)
4407                 {
4408                         u16 a = myrand() % 16;
4409                         u16 amount = iron_amount * a*a*a / 1000;
4410                         for(s16 i=0; i<amount; i++)
4411                         {
4412                                 v3s16 cp(
4413                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4414                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
4415                                         (myrand()%(MAP_BLOCKSIZE-2))+1
4416                                 );
4417
4418                                 MapNode n;
4419                                 n.d = CONTENT_STONE;
4420                                 n.param = MINERAL_IRON;
4421
4422                                 for(u16 i=0; i<27; i++)
4423                                 {
4424                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
4425                                                 if(myrand()%8 == 0)
4426                                                         block->setNode(cp+g_27dirs[i], n);
4427                                 }
4428                         }
4429                 }
4430         }
4431         
4432         /*
4433                 Create a few rats in empty blocks underground
4434         */
4435         if(completely_underground)
4436         {
4437                 //for(u16 i=0; i<2; i++)
4438                 {
4439                         v3s16 cp(
4440                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4441                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
4442                                 (myrand()%(MAP_BLOCKSIZE-2))+1
4443                         );
4444
4445                         // Check that the place is empty
4446                         //if(!is_ground_content(block->getNode(cp).d))
4447                         if(1)
4448                         {
4449                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp, BS));
4450                                 block->addObject(obj);
4451                         }
4452                 }
4453         }
4454         
4455         /*
4456                 Add block to sector.
4457         */
4458         sector->insertBlock(block);
4459         
4460         // Lighting is invalid after generation.
4461         block->setLightingExpired(true);
4462         
4463 #if 0
4464         /*
4465                 Debug information
4466         */
4467         dstream
4468         <<"lighting_invalidated_blocks.size()"
4469         <<", has_caves"
4470         <<", completely_ug"
4471         <<", some_part_ug"
4472         <<"  "<<lighting_invalidated_blocks.size()
4473         <<", "<<has_caves
4474         <<", "<<completely_underground
4475         <<", "<<some_part_underground
4476         <<std::endl;
4477 #endif
4478
4479         return block;
4480 }
4481
4482 MapBlock * ServerMap::createBlock(v3s16 p)
4483 {
4484         DSTACK("%s: p=(%d,%d,%d)",
4485                         __FUNCTION_NAME, p.X, p.Y, p.Z);
4486         
4487         /*
4488                 Do not create over-limit
4489         */
4490         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4491         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4492         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4493         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4494         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4495         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4496                 throw InvalidPositionException("createBlock(): pos. over limit");
4497         
4498         v2s16 p2d(p.X, p.Z);
4499         s16 block_y = p.Y;
4500         /*
4501                 This will create or load a sector if not found in memory.
4502                 If block exists on disk, it will be loaded.
4503
4504                 NOTE: On old save formats, this will be slow, as it generates
4505                       lighting on blocks for them.
4506         */
4507         ServerMapSector *sector;
4508         try{
4509                 sector = (ServerMapSector*)createSector(p2d);
4510                 assert(sector->getId() == MAPSECTOR_SERVER);
4511         }
4512         catch(InvalidPositionException &e)
4513         {
4514                 dstream<<"createBlock: createSector() failed"<<std::endl;
4515                 throw e;
4516         }
4517         /*
4518                 NOTE: This should not be done, or at least the exception
4519                 should not be passed on as std::exception, because it
4520                 won't be catched at all.
4521         */
4522         /*catch(std::exception &e)
4523         {
4524                 dstream<<"createBlock: createSector() failed: "
4525                                 <<e.what()<<std::endl;
4526                 throw e;
4527         }*/
4528
4529         /*
4530                 Try to get a block from the sector
4531         */
4532
4533         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4534         if(block)
4535                 return block;
4536         // Create blank
4537         block = sector->createBlankBlock(block_y);
4538         return block;
4539 }
4540
4541 MapBlock * ServerMap::emergeBlock(
4542                 v3s16 p,
4543                 bool only_from_disk,
4544                 core::map<v3s16, MapBlock*> &changed_blocks,
4545                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
4546 )
4547 {
4548         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
4549                         __FUNCTION_NAME,
4550                         p.X, p.Y, p.Z, only_from_disk);
4551         
4552         /*
4553                 Do not generate over-limit
4554         */
4555         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4556         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4557         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4558         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4559         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
4560         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
4561                 throw InvalidPositionException("emergeBlock(): pos. over limit");
4562         
4563         v2s16 p2d(p.X, p.Z);
4564         s16 block_y = p.Y;
4565         /*
4566                 This will create or load a sector if not found in memory.
4567                 If block exists on disk, it will be loaded.
4568         */
4569         ServerMapSector *sector;
4570         try{
4571                 sector = (ServerMapSector*)emergeSector(p2d, changed_blocks);
4572                 assert(sector->getId() == MAPSECTOR_SERVER);
4573         }
4574         catch(InvalidPositionException &e)
4575         {
4576                 dstream<<"emergeBlock: emergeSector() failed: "
4577                                 <<e.what()<<std::endl;
4578                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4579                                 <<std::endl
4580                                 <<"You could try to delete it."<<std::endl;
4581                 throw e;
4582         }
4583         catch(VersionMismatchException &e)
4584         {
4585                 dstream<<"emergeBlock: emergeSector() failed: "
4586                                 <<e.what()<<std::endl;
4587                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4588                                 <<std::endl
4589                                 <<"You could try to delete it."<<std::endl;
4590                 throw e;
4591         }
4592         /*
4593                 NOTE: This should not be done, or at least the exception
4594                 should not be passed on as std::exception, because it
4595                 won't be catched at all.
4596         */
4597         /*catch(std::exception &e)
4598         {
4599                 dstream<<"emergeBlock: emergeSector() failed: "
4600                                 <<e.what()<<std::endl;
4601                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
4602                                 <<std::endl
4603                                 <<"You could try to delete it."<<std::endl;
4604                 throw e;
4605         }*/
4606
4607         /*
4608                 Try to get a block from the sector
4609         */
4610
4611         bool does_not_exist = false;
4612         bool lighting_expired = false;
4613         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
4614
4615         if(block == NULL)
4616         {
4617                 does_not_exist = true;
4618         }
4619         else if(block->isDummy() == true)
4620         {
4621                 does_not_exist = true;
4622         }
4623         else if(block->getLightingExpired())
4624         {
4625                 lighting_expired = true;
4626         }
4627         else
4628         {
4629                 // Valid block
4630                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
4631                 return block;
4632         }
4633         
4634         /*
4635                 If block was not found on disk and not going to generate a
4636                 new one, make sure there is a dummy block in place.
4637         */
4638         if(only_from_disk && (does_not_exist || lighting_expired))
4639         {
4640                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
4641
4642                 if(block == NULL)
4643                 {
4644                         // Create dummy block
4645                         block = new MapBlock(this, p, true);
4646
4647                         // Add block to sector
4648                         sector->insertBlock(block);
4649                 }
4650                 // Done.
4651                 return block;
4652         }
4653
4654         //dstream<<"Not found on disk, generating."<<std::endl;
4655         // 0ms
4656         //TimeTaker("emergeBlock() generate");
4657
4658         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
4659
4660         /*
4661                 If the block doesn't exist, generate the block.
4662         */
4663         if(does_not_exist)
4664         {
4665                 block = generateBlock(p, block, sector, changed_blocks,
4666                                 lighting_invalidated_blocks); 
4667         }
4668
4669         if(lighting_expired)
4670         {
4671                 lighting_invalidated_blocks.insert(p, block);
4672         }
4673
4674         /*
4675                 Initially update sunlight
4676         */
4677         
4678         {
4679                 core::map<v3s16, bool> light_sources;
4680                 bool black_air_left = false;
4681                 bool bottom_invalid =
4682                                 block->propagateSunlight(light_sources, true,
4683                                 &black_air_left, true);
4684
4685                 // If sunlight didn't reach everywhere and part of block is
4686                 // above ground, lighting has to be properly updated
4687                 //if(black_air_left && some_part_underground)
4688                 if(black_air_left)
4689                 {
4690                         lighting_invalidated_blocks[block->getPos()] = block;
4691                 }
4692
4693                 if(bottom_invalid)
4694                 {
4695                         lighting_invalidated_blocks[block->getPos()] = block;
4696                 }
4697         }
4698         
4699         return block;
4700 }
4701
4702 s16 ServerMap::findGroundLevel(v2s16 p2d)
4703 {
4704         /*
4705                 Uh, just do something random...
4706         */
4707         // Find existing map from top to down
4708         s16 max=63;
4709         s16 min=-64;
4710         v3s16 p(p2d.X, max, p2d.Y);
4711         for(; p.Y>min; p.Y--)
4712         {
4713                 MapNode n = getNodeNoEx(p);
4714                 if(n.d != CONTENT_IGNORE)
4715                         break;
4716         }
4717         if(p.Y == min)
4718                 goto plan_b;
4719         // If this node is not air, go to plan b
4720         if(getNodeNoEx(p).d != CONTENT_AIR)
4721                 goto plan_b;
4722         // Search existing walkable and return it
4723         for(; p.Y>min; p.Y--)
4724         {
4725                 MapNode n = getNodeNoEx(p);
4726                 if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
4727                         return p.Y;
4728         }
4729         // Move to plan b
4730 plan_b:
4731         /*
4732                 Plan B: Get from map generator perlin noise function
4733         */
4734         double level = base_rock_level_2d(m_seed, p2d);
4735         return (s16)level;
4736 }
4737
4738 void ServerMap::createDir(std::string path)
4739 {
4740         if(fs::CreateDir(path) == false)
4741         {
4742                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
4743                                 <<"\""<<path<<"\""<<std::endl;
4744                 throw BaseException("ServerMap failed to create directory");
4745         }
4746 }
4747
4748 std::string ServerMap::getSectorSubDir(v2s16 pos)
4749 {
4750         char cc[9];
4751         snprintf(cc, 9, "%.4x%.4x",
4752                         (unsigned int)pos.X&0xffff,
4753                         (unsigned int)pos.Y&0xffff);
4754
4755         return std::string(cc);
4756 }
4757
4758 std::string ServerMap::getSectorDir(v2s16 pos)
4759 {
4760         return m_savedir + "/sectors/" + getSectorSubDir(pos);
4761 }
4762
4763 v2s16 ServerMap::getSectorPos(std::string dirname)
4764 {
4765         if(dirname.size() != 8)
4766                 throw InvalidFilenameException("Invalid sector directory name");
4767         unsigned int x, y;
4768         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
4769         if(r != 2)
4770                 throw InvalidFilenameException("Invalid sector directory name");
4771         v2s16 pos((s16)x, (s16)y);
4772         return pos;
4773 }
4774
4775 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
4776 {
4777         v2s16 p2d = getSectorPos(sectordir);
4778
4779         if(blockfile.size() != 4){
4780                 throw InvalidFilenameException("Invalid block filename");
4781         }
4782         unsigned int y;
4783         int r = sscanf(blockfile.c_str(), "%4x", &y);
4784         if(r != 1)
4785                 throw InvalidFilenameException("Invalid block filename");
4786         return v3s16(p2d.X, y, p2d.Y);
4787 }
4788
4789 void ServerMap::save(bool only_changed)
4790 {
4791         DSTACK(__FUNCTION_NAME);
4792         if(m_map_saving_enabled == false)
4793         {
4794                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
4795                 return;
4796         }
4797         
4798         if(only_changed == false)
4799                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
4800                                 <<std::endl;
4801         
4802         saveMapMeta();
4803         saveChunkMeta();
4804         
4805         u32 sector_meta_count = 0;
4806         u32 block_count = 0;
4807         
4808         { //sectorlock
4809         JMutexAutoLock lock(m_sector_mutex);
4810         
4811         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
4812         for(; i.atEnd() == false; i++)
4813         {
4814                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
4815                 assert(sector->getId() == MAPSECTOR_SERVER);
4816         
4817                 if(sector->differs_from_disk || only_changed == false)
4818                 {
4819                         saveSectorMeta(sector);
4820                         sector_meta_count++;
4821                 }
4822                 core::list<MapBlock*> blocks;
4823                 sector->getBlocks(blocks);
4824                 core::list<MapBlock*>::Iterator j;
4825                 for(j=blocks.begin(); j!=blocks.end(); j++)
4826                 {
4827                         MapBlock *block = *j;
4828                         if(block->getChangedFlag() || only_changed == false)
4829                         {
4830                                 saveBlock(block);
4831                                 block_count++;
4832
4833                                 /*dstream<<"ServerMap: Written block ("
4834                                                 <<block->getPos().X<<","
4835                                                 <<block->getPos().Y<<","
4836                                                 <<block->getPos().Z<<")"
4837                                                 <<std::endl;*/
4838                         }
4839                 }
4840         }
4841
4842         }//sectorlock
4843         
4844         /*
4845                 Only print if something happened or saved whole map
4846         */
4847         if(only_changed == false || sector_meta_count != 0
4848                         || block_count != 0)
4849         {
4850                 dstream<<DTIME<<"ServerMap: Written: "
4851                                 <<sector_meta_count<<" sector metadata files, "
4852                                 <<block_count<<" block files"
4853                                 <<std::endl;
4854         }
4855 }
4856
4857 void ServerMap::loadAll()
4858 {
4859         DSTACK(__FUNCTION_NAME);
4860         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
4861         
4862         loadMapMeta();
4863         loadChunkMeta();
4864
4865         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
4866
4867         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
4868         
4869         JMutexAutoLock lock(m_sector_mutex);
4870         
4871         s32 counter = 0;
4872         s32 printed_counter = -100000;
4873         s32 count = list.size();
4874
4875         std::vector<fs::DirListNode>::iterator i;
4876         for(i=list.begin(); i!=list.end(); i++)
4877         {
4878                 if(counter > printed_counter + 10)
4879                 {
4880                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
4881                         printed_counter = counter;
4882                 }
4883                 counter++;
4884
4885                 MapSector *sector = NULL;
4886
4887                 // We want directories
4888                 if(i->dir == false)
4889                         continue;
4890                 try{
4891                         sector = loadSectorMeta(i->name);
4892                 }
4893                 catch(InvalidFilenameException &e)
4894                 {
4895                         // This catches unknown crap in directory
4896                 }
4897                 
4898                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
4899                                 (m_savedir+"/sectors/"+i->name);
4900                 std::vector<fs::DirListNode>::iterator i2;
4901                 for(i2=list2.begin(); i2!=list2.end(); i2++)
4902                 {
4903                         // We want files
4904                         if(i2->dir)
4905                                 continue;
4906                         try{
4907                                 loadBlock(i->name, i2->name, sector);
4908                         }
4909                         catch(InvalidFilenameException &e)
4910                         {
4911                                 // This catches unknown crap in directory
4912                         }
4913                 }
4914         }
4915         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
4916 }
4917
4918 #if 0
4919 void ServerMap::saveMasterHeightmap()
4920 {
4921         DSTACK(__FUNCTION_NAME);
4922         
4923         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
4924
4925         createDir(m_savedir);
4926         
4927         /*std::string fullpath = m_savedir + "/master_heightmap";
4928         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
4929         if(o.good() == false)
4930                 throw FileNotGoodException("Cannot open master heightmap");*/
4931         
4932         // Format used for writing
4933         //u8 version = SER_FMT_VER_HIGHEST;
4934 }
4935
4936 void ServerMap::loadMasterHeightmap()
4937 {
4938         DSTACK(__FUNCTION_NAME);
4939         
4940         dstream<<"DEPRECATED: "<<__FUNCTION_NAME<<std::endl;
4941
4942         /*std::string fullpath = m_savedir + "/master_heightmap";
4943         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4944         if(is.good() == false)
4945                 throw FileNotGoodException("Cannot open master heightmap");*/
4946 }
4947 #endif
4948
4949 void ServerMap::saveMapMeta()
4950 {
4951         DSTACK(__FUNCTION_NAME);
4952         
4953         dstream<<"INFO: ServerMap::saveMapMeta(): "
4954                         <<"seed="<<m_seed<<", chunksize="<<m_chunksize
4955                         <<std::endl;
4956
4957         createDir(m_savedir);
4958         
4959         std::string fullpath = m_savedir + "/map_meta.txt";
4960         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
4961         if(os.good() == false)
4962         {
4963                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
4964                                 <<"could not open"<<fullpath<<std::endl;
4965                 throw FileNotGoodException("Cannot open chunk metadata");
4966         }
4967         
4968         Settings params;
4969         params.setU64("seed", m_seed);
4970         params.setS32("chunksize", m_chunksize);
4971
4972         params.writeLines(os);
4973
4974         os<<"[end_of_params]\n";
4975         
4976 }
4977
4978 void ServerMap::loadMapMeta()
4979 {
4980         DSTACK(__FUNCTION_NAME);
4981         
4982         dstream<<"INFO: ServerMap::loadMapMeta(): Loading chunk metadata"
4983                         <<std::endl;
4984
4985         std::string fullpath = m_savedir + "/map_meta.txt";
4986         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
4987         if(is.good() == false)
4988         {
4989                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
4990                                 <<"could not open"<<fullpath<<std::endl;
4991                 throw FileNotGoodException("Cannot open chunk metadata");
4992         }
4993
4994         Settings params;
4995
4996         for(;;)
4997         {
4998                 if(is.eof())
4999                         throw SerializationError
5000                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
5001                 std::string line;
5002                 std::getline(is, line);
5003                 std::string trimmedline = trim(line);
5004                 if(trimmedline == "[end_of_params]")
5005                         break;
5006                 params.parseConfigLine(line);
5007         }
5008
5009         m_seed = params.getU64("seed");
5010         m_chunksize = params.getS32("chunksize");
5011
5012         dstream<<"INFO: ServerMap::loadMapMeta(): "
5013                         <<"seed="<<m_seed<<", chunksize="<<m_chunksize
5014                         <<std::endl;
5015 }
5016
5017 void ServerMap::saveChunkMeta()
5018 {
5019         DSTACK(__FUNCTION_NAME);
5020         
5021         u32 count = m_chunks.size();
5022
5023         dstream<<"INFO: ServerMap::saveChunkMeta(): Saving metadata of "
5024                         <<count<<" chunks"<<std::endl;
5025
5026         createDir(m_savedir);
5027         
5028         std::string fullpath = m_savedir + "/chunk_meta";
5029         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
5030         if(os.good() == false)
5031         {
5032                 dstream<<"ERROR: ServerMap::saveChunkMeta(): "
5033                                 <<"could not open"<<fullpath<<std::endl;
5034                 throw FileNotGoodException("Cannot open chunk metadata");
5035         }
5036         
5037         u8 version = 0;
5038         
5039         // Write version
5040         os.write((char*)&version, 1);
5041
5042         u8 buf[4];
5043         
5044         // Write count
5045         writeU32(buf, count);
5046         os.write((char*)buf, 4);
5047         
5048         for(core::map<v2s16, MapChunk*>::Iterator
5049                         i = m_chunks.getIterator();
5050                         i.atEnd()==false; i++)
5051         {
5052                 v2s16 p = i.getNode()->getKey();
5053                 MapChunk *chunk = i.getNode()->getValue();
5054                 // Write position
5055                 writeV2S16(buf, p);
5056                 os.write((char*)buf, 4);
5057                 // Write chunk data
5058                 chunk->serialize(os, version);
5059         }
5060 }
5061
5062 void ServerMap::loadChunkMeta()
5063 {
5064         DSTACK(__FUNCTION_NAME);
5065         
5066         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading chunk metadata"
5067                         <<std::endl;
5068
5069         std::string fullpath = m_savedir + "/chunk_meta";
5070         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5071         if(is.good() == false)
5072         {
5073                 dstream<<"ERROR: ServerMap::loadChunkMeta(): "
5074                                 <<"could not open"<<fullpath<<std::endl;
5075                 throw FileNotGoodException("Cannot open chunk metadata");
5076         }
5077
5078         u8 version = 0;
5079         
5080         // Read version
5081         is.read((char*)&version, 1);
5082
5083         u8 buf[4];
5084         
5085         // Read count
5086         is.read((char*)buf, 4);
5087         u32 count = readU32(buf);
5088
5089         dstream<<"INFO: ServerMap::loadChunkMeta(): Loading metadata of "
5090                         <<count<<" chunks"<<std::endl;
5091         
5092         for(u32 i=0; i<count; i++)
5093         {
5094                 v2s16 p;
5095                 MapChunk *chunk = new MapChunk();
5096                 // Read position
5097                 is.read((char*)buf, 4);
5098                 p = readV2S16(buf);
5099                 // Read chunk data
5100                 chunk->deSerialize(is, version);
5101                 m_chunks.insert(p, chunk);
5102         }
5103 }
5104
5105 void ServerMap::saveSectorMeta(ServerMapSector *sector)
5106 {
5107         DSTACK(__FUNCTION_NAME);
5108         // Format used for writing
5109         u8 version = SER_FMT_VER_HIGHEST;
5110         // Get destination
5111         v2s16 pos = sector->getPos();
5112         createDir(m_savedir);
5113         createDir(m_savedir+"/sectors");
5114         std::string dir = getSectorDir(pos);
5115         createDir(dir);
5116         
5117         std::string fullpath = dir + "/meta";
5118         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5119         if(o.good() == false)
5120                 throw FileNotGoodException("Cannot open sector metafile");
5121
5122         sector->serialize(o, version);
5123         
5124         sector->differs_from_disk = false;
5125 }
5126
5127 MapSector* ServerMap::loadSectorMeta(std::string dirname)
5128 {
5129         DSTACK(__FUNCTION_NAME);
5130         // Get destination
5131         v2s16 p2d = getSectorPos(dirname);
5132         std::string dir = m_savedir + "/sectors/" + dirname;
5133         
5134         std::string fullpath = dir + "/meta";
5135         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5136         if(is.good() == false)
5137                 throw FileNotGoodException("Cannot open sector metafile");
5138
5139         ServerMapSector *sector = ServerMapSector::deSerialize
5140                         (is, this, p2d, m_sectors);
5141         
5142         sector->differs_from_disk = false;
5143
5144         return sector;
5145 }
5146
5147 bool ServerMap::loadSectorFull(v2s16 p2d)
5148 {
5149         DSTACK(__FUNCTION_NAME);
5150         std::string sectorsubdir = getSectorSubDir(p2d);
5151
5152         MapSector *sector = NULL;
5153
5154         JMutexAutoLock lock(m_sector_mutex);
5155
5156         try{
5157                 sector = loadSectorMeta(sectorsubdir);
5158         }
5159         catch(InvalidFilenameException &e)
5160         {
5161                 return false;
5162         }
5163         catch(FileNotGoodException &e)
5164         {
5165                 return false;
5166         }
5167         catch(std::exception &e)
5168         {
5169                 return false;
5170         }
5171         
5172         /*
5173                 Load blocks
5174         */
5175         std::vector<fs::DirListNode> list2 = fs::GetDirListing
5176                         (m_savedir+"/sectors/"+sectorsubdir);
5177         std::vector<fs::DirListNode>::iterator i2;
5178         for(i2=list2.begin(); i2!=list2.end(); i2++)
5179         {
5180                 // We want files
5181                 if(i2->dir)
5182                         continue;
5183                 try{
5184                         loadBlock(sectorsubdir, i2->name, sector);
5185                 }
5186                 catch(InvalidFilenameException &e)
5187                 {
5188                         // This catches unknown crap in directory
5189                 }
5190         }
5191         return true;
5192 }
5193
5194 void ServerMap::saveBlock(MapBlock *block)
5195 {
5196         DSTACK(__FUNCTION_NAME);
5197         /*
5198                 Dummy blocks are not written
5199         */
5200         if(block->isDummy())
5201         {
5202                 /*v3s16 p = block->getPos();
5203                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
5204                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
5205                 return;
5206         }
5207
5208         // Format used for writing
5209         u8 version = SER_FMT_VER_HIGHEST;
5210         // Get destination
5211         v3s16 p3d = block->getPos();
5212         v2s16 p2d(p3d.X, p3d.Z);
5213         createDir(m_savedir);
5214         createDir(m_savedir+"/sectors");
5215         std::string dir = getSectorDir(p2d);
5216         createDir(dir);
5217         
5218         // Block file is map/sectors/xxxxxxxx/xxxx
5219         char cc[5];
5220         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
5221         std::string fullpath = dir + "/" + cc;
5222         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
5223         if(o.good() == false)
5224                 throw FileNotGoodException("Cannot open block data");
5225
5226         /*
5227                 [0] u8 serialization version
5228                 [1] data
5229         */
5230         o.write((char*)&version, 1);
5231         
5232         block->serialize(o, version);
5233
5234         /*
5235                 Versions up from 9 have block objects.
5236         */
5237         if(version >= 9)
5238         {
5239                 block->serializeObjects(o, version);
5240         }
5241         
5242         /*
5243                 Versions up from 15 have static objects.
5244         */
5245         if(version >= 15)
5246         {
5247                 block->m_static_objects.serialize(o);
5248         }
5249         
5250         // We just wrote it to the disk
5251         block->resetChangedFlag();
5252 }
5253
5254 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
5255 {
5256         DSTACK(__FUNCTION_NAME);
5257
5258         // Block file is map/sectors/xxxxxxxx/xxxx
5259         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
5260         try{
5261
5262                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
5263                 if(is.good() == false)
5264                         throw FileNotGoodException("Cannot open block file");
5265                 
5266                 v3s16 p3d = getBlockPos(sectordir, blockfile);
5267                 v2s16 p2d(p3d.X, p3d.Z);
5268                 
5269                 assert(sector->getPos() == p2d);
5270                 
5271                 u8 version = SER_FMT_VER_INVALID;
5272                 is.read((char*)&version, 1);
5273
5274                 if(is.fail())
5275                         throw SerializationError("ServerMap::loadBlock(): Failed"
5276                                         " to read MapBlock version");
5277
5278                 /*u32 block_size = MapBlock::serializedLength(version);
5279                 SharedBuffer<u8> data(block_size);
5280                 is.read((char*)*data, block_size);*/
5281
5282                 // This will always return a sector because we're the server
5283                 //MapSector *sector = emergeSector(p2d);
5284
5285                 MapBlock *block = NULL;
5286                 bool created_new = false;
5287                 try{
5288                         block = sector->getBlockNoCreate(p3d.Y);
5289                 }
5290                 catch(InvalidPositionException &e)
5291                 {
5292                         block = sector->createBlankBlockNoInsert(p3d.Y);
5293                         created_new = true;
5294                 }
5295                 
5296                 // deserialize block data
5297                 block->deSerialize(is, version);
5298                 
5299                 /*
5300                         Versions up from 9 have block objects.
5301                 */
5302                 if(version >= 9)
5303                 {
5304                         block->updateObjects(is, version, NULL, 0);
5305                 }
5306
5307                 /*
5308                         Versions up from 15 have static objects.
5309                 */
5310                 if(version >= 15)
5311                 {
5312                         block->m_static_objects.deSerialize(is);
5313                 }
5314                 
5315                 if(created_new)
5316                         sector->insertBlock(block);
5317                 
5318                 /*
5319                         Convert old formats to new and save
5320                 */
5321
5322                 // Save old format blocks in new format
5323                 if(version < SER_FMT_VER_HIGHEST)
5324                 {
5325                         saveBlock(block);
5326                 }
5327                 
5328                 // We just loaded it from the disk, so it's up-to-date.
5329                 block->resetChangedFlag();
5330
5331         }
5332         catch(SerializationError &e)
5333         {
5334                 dstream<<"WARNING: Invalid block data on disk "
5335                                 "(SerializationError). Ignoring. "
5336                                 "A new one will be generated."
5337                                 <<std::endl;
5338
5339                 // TODO: Backup file; name is in fullpath.
5340         }
5341 }
5342
5343 void ServerMap::PrintInfo(std::ostream &out)
5344 {
5345         out<<"ServerMap: ";
5346 }
5347
5348 #ifndef SERVER
5349
5350 /*
5351         ClientMap
5352 */
5353
5354 ClientMap::ClientMap(
5355                 Client *client,
5356                 MapDrawControl &control,
5357                 scene::ISceneNode* parent,
5358                 scene::ISceneManager* mgr,
5359                 s32 id
5360 ):
5361         Map(dout_client),
5362         scene::ISceneNode(parent, mgr, id),
5363         m_client(client),
5364         m_control(control),
5365         m_camera_position(0,0,0),
5366         m_camera_direction(0,0,1)
5367 {
5368         m_camera_mutex.Init();
5369         assert(m_camera_mutex.IsInitialized());
5370         
5371         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
5372                         BS*1000000,BS*1000000,BS*1000000);
5373 }
5374
5375 ClientMap::~ClientMap()
5376 {
5377         /*JMutexAutoLock lock(mesh_mutex);
5378         
5379         if(mesh != NULL)
5380         {
5381                 mesh->drop();
5382                 mesh = NULL;
5383         }*/
5384 }
5385
5386 MapSector * ClientMap::emergeSector(v2s16 p2d)
5387 {
5388         DSTACK(__FUNCTION_NAME);
5389         // Check that it doesn't exist already
5390         try{
5391                 return getSectorNoGenerate(p2d);
5392         }
5393         catch(InvalidPositionException &e)
5394         {
5395         }
5396         
5397         // Create a sector
5398         ClientMapSector *sector = new ClientMapSector(this, p2d);
5399         
5400         {
5401                 JMutexAutoLock lock(m_sector_mutex);
5402                 m_sectors.insert(p2d, sector);
5403         }
5404         
5405         return sector;
5406 }
5407
5408 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
5409 {
5410         DSTACK(__FUNCTION_NAME);
5411         ClientMapSector *sector = NULL;
5412
5413         JMutexAutoLock lock(m_sector_mutex);
5414         
5415         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
5416
5417         if(n != NULL)
5418         {
5419                 sector = (ClientMapSector*)n->getValue();
5420                 assert(sector->getId() == MAPSECTOR_CLIENT);
5421         }
5422         else
5423         {
5424                 sector = new ClientMapSector(this, p2d);
5425                 {
5426                         JMutexAutoLock lock(m_sector_mutex);
5427                         m_sectors.insert(p2d, sector);
5428                 }
5429         }
5430
5431         sector->deSerialize(is);
5432 }
5433
5434 void ClientMap::OnRegisterSceneNode()
5435 {
5436         if(IsVisible)
5437         {
5438                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
5439                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
5440         }
5441
5442         ISceneNode::OnRegisterSceneNode();
5443 }
5444
5445 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
5446 {
5447         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
5448         DSTACK(__FUNCTION_NAME);
5449
5450         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
5451
5452         /*
5453                 Get time for measuring timeout.
5454                 
5455                 Measuring time is very useful for long delays when the
5456                 machine is swapping a lot.
5457         */
5458         int time1 = time(0);
5459
5460         //u32 daynight_ratio = m_client->getDayNightRatio();
5461
5462         m_camera_mutex.Lock();
5463         v3f camera_position = m_camera_position;
5464         v3f camera_direction = m_camera_direction;
5465         m_camera_mutex.Unlock();
5466
5467         /*
5468                 Get all blocks and draw all visible ones
5469         */
5470
5471         v3s16 cam_pos_nodes(
5472                         camera_position.X / BS,
5473                         camera_position.Y / BS,
5474                         camera_position.Z / BS);
5475
5476         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
5477
5478         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
5479         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
5480
5481         // Take a fair amount as we will be dropping more out later
5482         v3s16 p_blocks_min(
5483                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
5484                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
5485                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
5486         v3s16 p_blocks_max(
5487                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
5488                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
5489                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
5490         
5491         u32 vertex_count = 0;
5492         
5493         // For limiting number of mesh updates per frame
5494         u32 mesh_update_count = 0;
5495         
5496         u32 blocks_would_have_drawn = 0;
5497         u32 blocks_drawn = 0;
5498
5499         //NOTE: The sectors map should be locked but we're not doing it
5500         // because it'd cause too much delays
5501
5502         int timecheck_counter = 0;
5503         core::map<v2s16, MapSector*>::Iterator si;
5504         si = m_sectors.getIterator();
5505         for(; si.atEnd() == false; si++)
5506         {
5507                 {
5508                         timecheck_counter++;
5509                         if(timecheck_counter > 50)
5510                         {
5511                                 timecheck_counter = 0;
5512                                 int time2 = time(0);
5513                                 if(time2 > time1 + 4)
5514                                 {
5515                                         dstream<<"ClientMap::renderMap(): "
5516                                                 "Rendering takes ages, returning."
5517                                                 <<std::endl;
5518                                         return;
5519                                 }
5520                         }
5521                 }
5522
5523                 MapSector *sector = si.getNode()->getValue();
5524                 v2s16 sp = sector->getPos();
5525                 
5526                 if(m_control.range_all == false)
5527                 {
5528                         if(sp.X < p_blocks_min.X
5529                         || sp.X > p_blocks_max.X
5530                         || sp.Y < p_blocks_min.Z
5531                         || sp.Y > p_blocks_max.Z)
5532                                 continue;
5533                 }
5534
5535                 core::list< MapBlock * > sectorblocks;
5536                 sector->getBlocks(sectorblocks);
5537                 
5538                 /*
5539                         Draw blocks
5540                 */
5541
5542                 core::list< MapBlock * >::Iterator i;
5543                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5544                 {
5545                         MapBlock *block = *i;
5546
5547                         /*
5548                                 Compare block position to camera position, skip
5549                                 if not seen on display
5550                         */
5551                         
5552                         float range = 100000 * BS;
5553                         if(m_control.range_all == false)
5554                                 range = m_control.wanted_range * BS;
5555                         
5556                         float d = 0.0;
5557                         if(isBlockInSight(block->getPos(), camera_position,
5558                                         camera_direction, range, &d) == false)
5559                         {
5560                                 continue;
5561                         }
5562                         
5563                         // This is ugly (spherical distance limit?)
5564                         /*if(m_control.range_all == false &&
5565                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
5566                                 continue;*/
5567
5568 #if 1
5569                         /*
5570                                 Update expired mesh (used for day/night change)
5571
5572                                 It doesn't work exactly like it should now with the
5573                                 tasked mesh update but whatever.
5574                         */
5575
5576                         bool mesh_expired = false;
5577                         
5578                         {
5579                                 JMutexAutoLock lock(block->mesh_mutex);
5580
5581                                 mesh_expired = block->getMeshExpired();
5582
5583                                 // Mesh has not been expired and there is no mesh:
5584                                 // block has no content
5585                                 if(block->mesh == NULL && mesh_expired == false)
5586                                         continue;
5587                         }
5588
5589                         f32 faraway = BS*50;
5590                         //f32 faraway = m_control.wanted_range * BS;
5591                         
5592                         /*
5593                                 This has to be done with the mesh_mutex unlocked
5594                         */
5595                         // Pretty random but this should work somewhat nicely
5596                         if(mesh_expired && (
5597                                         (mesh_update_count < 3
5598                                                 && (d < faraway || mesh_update_count < 2)
5599                                         )
5600                                         || 
5601                                         (m_control.range_all && mesh_update_count < 20)
5602                                 )
5603                         )
5604                         /*if(mesh_expired && mesh_update_count < 6
5605                                         && (d < faraway || mesh_update_count < 3))*/
5606                         {
5607                                 mesh_update_count++;
5608
5609                                 // Mesh has been expired: generate new mesh
5610                                 //block->updateMesh(daynight_ratio);
5611                                 m_client->addUpdateMeshTask(block->getPos());
5612
5613                                 mesh_expired = false;
5614                         }
5615                         
5616 #endif
5617                         /*
5618                                 Draw the faces of the block
5619                         */
5620                         {
5621                                 JMutexAutoLock lock(block->mesh_mutex);
5622
5623                                 scene::SMesh *mesh = block->mesh;
5624
5625                                 if(mesh == NULL)
5626                                         continue;
5627                                 
5628                                 blocks_would_have_drawn++;
5629                                 if(blocks_drawn >= m_control.wanted_max_blocks
5630                                                 && m_control.range_all == false
5631                                                 && d > m_control.wanted_min_range * BS)
5632                                         continue;
5633                                 blocks_drawn++;
5634
5635                                 u32 c = mesh->getMeshBufferCount();
5636
5637                                 for(u32 i=0; i<c; i++)
5638                                 {
5639                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
5640                                         const video::SMaterial& material = buf->getMaterial();
5641                                         video::IMaterialRenderer* rnd =
5642                                                         driver->getMaterialRenderer(material.MaterialType);
5643                                         bool transparent = (rnd && rnd->isTransparent());
5644                                         // Render transparent on transparent pass and likewise.
5645                                         if(transparent == is_transparent_pass)
5646                                         {
5647                                                 /*
5648                                                         This *shouldn't* hurt too much because Irrlicht
5649                                                         doesn't change opengl textures if the old
5650                                                         material is set again.
5651                                                 */
5652                                                 driver->setMaterial(buf->getMaterial());
5653                                                 driver->drawMeshBuffer(buf);
5654                                                 vertex_count += buf->getVertexCount();
5655                                         }
5656                                 }
5657                         }
5658                 } // foreach sectorblocks
5659         }
5660         
5661         m_control.blocks_drawn = blocks_drawn;
5662         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
5663
5664         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
5665                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
5666 }
5667
5668 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
5669                 core::map<v3s16, MapBlock*> *affected_blocks)
5670 {
5671         bool changed = false;
5672         /*
5673                 Add it to all blocks touching it
5674         */
5675         v3s16 dirs[7] = {
5676                 v3s16(0,0,0), // this
5677                 v3s16(0,0,1), // back
5678                 v3s16(0,1,0), // top
5679                 v3s16(1,0,0), // right
5680                 v3s16(0,0,-1), // front
5681                 v3s16(0,-1,0), // bottom
5682                 v3s16(-1,0,0), // left
5683         };
5684         for(u16 i=0; i<7; i++)
5685         {
5686                 v3s16 p2 = p + dirs[i];
5687                 // Block position of neighbor (or requested) node
5688                 v3s16 blockpos = getNodeBlockPos(p2);
5689                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5690                 if(blockref == NULL)
5691                         continue;
5692                 // Relative position of requested node
5693                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5694                 if(blockref->setTempMod(relpos, mod))
5695                 {
5696                         changed = true;
5697                 }
5698         }
5699         if(changed && affected_blocks!=NULL)
5700         {
5701                 for(u16 i=0; i<7; i++)
5702                 {
5703                         v3s16 p2 = p + dirs[i];
5704                         // Block position of neighbor (or requested) node
5705                         v3s16 blockpos = getNodeBlockPos(p2);
5706                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5707                         if(blockref == NULL)
5708                                 continue;
5709                         affected_blocks->insert(blockpos, blockref);
5710                 }
5711         }
5712         return changed;
5713 }
5714
5715 bool ClientMap::clearTempMod(v3s16 p,
5716                 core::map<v3s16, MapBlock*> *affected_blocks)
5717 {
5718         bool changed = false;
5719         v3s16 dirs[7] = {
5720                 v3s16(0,0,0), // this
5721                 v3s16(0,0,1), // back
5722                 v3s16(0,1,0), // top
5723                 v3s16(1,0,0), // right
5724                 v3s16(0,0,-1), // front
5725                 v3s16(0,-1,0), // bottom
5726                 v3s16(-1,0,0), // left
5727         };
5728         for(u16 i=0; i<7; i++)
5729         {
5730                 v3s16 p2 = p + dirs[i];
5731                 // Block position of neighbor (or requested) node
5732                 v3s16 blockpos = getNodeBlockPos(p2);
5733                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5734                 if(blockref == NULL)
5735                         continue;
5736                 // Relative position of requested node
5737                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
5738                 if(blockref->clearTempMod(relpos))
5739                 {
5740                         changed = true;
5741                 }
5742         }
5743         if(changed && affected_blocks!=NULL)
5744         {
5745                 for(u16 i=0; i<7; i++)
5746                 {
5747                         v3s16 p2 = p + dirs[i];
5748                         // Block position of neighbor (or requested) node
5749                         v3s16 blockpos = getNodeBlockPos(p2);
5750                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
5751                         if(blockref == NULL)
5752                                 continue;
5753                         affected_blocks->insert(blockpos, blockref);
5754                 }
5755         }
5756         return changed;
5757 }
5758
5759 void ClientMap::expireMeshes(bool only_daynight_diffed)
5760 {
5761         TimeTaker timer("expireMeshes()");
5762
5763         core::map<v2s16, MapSector*>::Iterator si;
5764         si = m_sectors.getIterator();
5765         for(; si.atEnd() == false; si++)
5766         {
5767                 MapSector *sector = si.getNode()->getValue();
5768
5769                 core::list< MapBlock * > sectorblocks;
5770                 sector->getBlocks(sectorblocks);
5771                 
5772                 core::list< MapBlock * >::Iterator i;
5773                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
5774                 {
5775                         MapBlock *block = *i;
5776
5777                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
5778                         {
5779                                 continue;
5780                         }
5781                         
5782                         {
5783                                 JMutexAutoLock lock(block->mesh_mutex);
5784                                 if(block->mesh != NULL)
5785                                 {
5786                                         /*block->mesh->drop();
5787                                         block->mesh = NULL;*/
5788                                         block->setMeshExpired(true);
5789                                 }
5790                         }
5791                 }
5792         }
5793 }
5794
5795 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
5796 {
5797         assert(mapType() == MAPTYPE_CLIENT);
5798
5799         try{
5800                 v3s16 p = blockpos + v3s16(0,0,0);
5801                 MapBlock *b = getBlockNoCreate(p);
5802                 b->updateMesh(daynight_ratio);
5803                 //b->setMeshExpired(true);
5804         }
5805         catch(InvalidPositionException &e){}
5806         // Leading edge
5807         try{
5808                 v3s16 p = blockpos + v3s16(-1,0,0);
5809                 MapBlock *b = getBlockNoCreate(p);
5810                 b->updateMesh(daynight_ratio);
5811                 //b->setMeshExpired(true);
5812         }
5813         catch(InvalidPositionException &e){}
5814         try{
5815                 v3s16 p = blockpos + v3s16(0,-1,0);
5816                 MapBlock *b = getBlockNoCreate(p);
5817                 b->updateMesh(daynight_ratio);
5818                 //b->setMeshExpired(true);
5819         }
5820         catch(InvalidPositionException &e){}
5821         try{
5822                 v3s16 p = blockpos + v3s16(0,0,-1);
5823                 MapBlock *b = getBlockNoCreate(p);
5824                 b->updateMesh(daynight_ratio);
5825                 //b->setMeshExpired(true);
5826         }
5827         catch(InvalidPositionException &e){}
5828 }
5829
5830 #if 0
5831 /*
5832         Update mesh of block in which the node is, and if the node is at the
5833         leading edge, update the appropriate leading blocks too.
5834 */
5835 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
5836 {
5837         v3s16 dirs[4] = {
5838                 v3s16(0,0,0),
5839                 v3s16(-1,0,0),
5840                 v3s16(0,-1,0),
5841                 v3s16(0,0,-1),
5842         };
5843         v3s16 blockposes[4];
5844         for(u32 i=0; i<4; i++)
5845         {
5846                 v3s16 np = nodepos + dirs[i];
5847                 blockposes[i] = getNodeBlockPos(np);
5848                 // Don't update mesh of block if it has been done already
5849                 bool already_updated = false;
5850                 for(u32 j=0; j<i; j++)
5851                 {
5852                         if(blockposes[j] == blockposes[i])
5853                         {
5854                                 already_updated = true;
5855                                 break;
5856                         }
5857                 }
5858                 if(already_updated)
5859                         continue;
5860                 // Update mesh
5861                 MapBlock *b = getBlockNoCreate(blockposes[i]);
5862                 b->updateMesh(daynight_ratio);
5863         }
5864 }
5865 #endif
5866
5867 void ClientMap::PrintInfo(std::ostream &out)
5868 {
5869         out<<"ClientMap: ";
5870 }
5871
5872 #endif // !SERVER
5873
5874 /*
5875         MapVoxelManipulator
5876 */
5877
5878 MapVoxelManipulator::MapVoxelManipulator(Map *map)
5879 {
5880         m_map = map;
5881 }
5882
5883 MapVoxelManipulator::~MapVoxelManipulator()
5884 {
5885         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
5886                         <<std::endl;*/
5887 }
5888
5889 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
5890 {
5891         TimeTaker timer1("emerge", &emerge_time);
5892
5893         // Units of these are MapBlocks
5894         v3s16 p_min = getNodeBlockPos(a.MinEdge);
5895         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
5896
5897         VoxelArea block_area_nodes
5898                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5899
5900         addArea(block_area_nodes);
5901
5902         for(s32 z=p_min.Z; z<=p_max.Z; z++)
5903         for(s32 y=p_min.Y; y<=p_max.Y; y++)
5904         for(s32 x=p_min.X; x<=p_max.X; x++)
5905         {
5906                 v3s16 p(x,y,z);
5907                 core::map<v3s16, bool>::Node *n;
5908                 n = m_loaded_blocks.find(p);
5909                 if(n != NULL)
5910                         continue;
5911                 
5912                 bool block_data_inexistent = false;
5913                 try
5914                 {
5915                         TimeTaker timer1("emerge load", &emerge_load_time);
5916
5917                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
5918                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
5919                                         <<" wanted area: ";
5920                         a.print(dstream);
5921                         dstream<<std::endl;*/
5922                         
5923                         MapBlock *block = m_map->getBlockNoCreate(p);
5924                         if(block->isDummy())
5925                                 block_data_inexistent = true;
5926                         else
5927                                 block->copyTo(*this);
5928                 }
5929                 catch(InvalidPositionException &e)
5930                 {
5931                         block_data_inexistent = true;
5932                 }
5933
5934                 if(block_data_inexistent)
5935                 {
5936                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
5937                         // Fill with VOXELFLAG_INEXISTENT
5938                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
5939                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
5940                         {
5941                                 s32 i = m_area.index(a.MinEdge.X,y,z);
5942                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
5943                         }
5944                 }
5945
5946                 m_loaded_blocks.insert(p, !block_data_inexistent);
5947         }
5948
5949         //dstream<<"emerge done"<<std::endl;
5950 }
5951
5952 /*
5953         SUGG: Add an option to only update eg. water and air nodes.
5954               This will make it interfere less with important stuff if
5955                   run on background.
5956 */
5957 void MapVoxelManipulator::blitBack
5958                 (core::map<v3s16, MapBlock*> & modified_blocks)
5959 {
5960         if(m_area.getExtent() == v3s16(0,0,0))
5961                 return;
5962         
5963         //TimeTaker timer1("blitBack");
5964
5965         /*dstream<<"blitBack(): m_loaded_blocks.size()="
5966                         <<m_loaded_blocks.size()<<std::endl;*/
5967         
5968         /*
5969                 Initialize block cache
5970         */
5971         v3s16 blockpos_last;
5972         MapBlock *block = NULL;
5973         bool block_checked_in_modified = false;
5974
5975         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
5976         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
5977         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
5978         {
5979                 v3s16 p(x,y,z);
5980
5981                 u8 f = m_flags[m_area.index(p)];
5982                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
5983                         continue;
5984
5985                 MapNode &n = m_data[m_area.index(p)];
5986                         
5987                 v3s16 blockpos = getNodeBlockPos(p);
5988                 
5989                 try
5990                 {
5991                         // Get block
5992                         if(block == NULL || blockpos != blockpos_last){
5993                                 block = m_map->getBlockNoCreate(blockpos);
5994                                 blockpos_last = blockpos;
5995                                 block_checked_in_modified = false;
5996                         }
5997                         
5998                         // Calculate relative position in block
5999                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
6000
6001                         // Don't continue if nothing has changed here
6002                         if(block->getNode(relpos) == n)
6003                                 continue;
6004
6005                         //m_map->setNode(m_area.MinEdge + p, n);
6006                         block->setNode(relpos, n);
6007                         
6008                         /*
6009                                 Make sure block is in modified_blocks
6010                         */
6011                         if(block_checked_in_modified == false)
6012                         {
6013                                 modified_blocks[blockpos] = block;
6014                                 block_checked_in_modified = true;
6015                         }
6016                 }
6017                 catch(InvalidPositionException &e)
6018                 {
6019                 }
6020         }
6021 }
6022
6023 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
6024                 MapVoxelManipulator(map)
6025 {
6026 }
6027
6028 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
6029 {
6030 }
6031
6032 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
6033 {
6034         // Just create the area so that it can be pointed to
6035         VoxelManipulator::emerge(a, caller_id);
6036 }
6037
6038 void ManualMapVoxelManipulator::initialEmerge(
6039                 v3s16 blockpos_min, v3s16 blockpos_max)
6040 {
6041         TimeTaker timer1("initialEmerge", &emerge_time);
6042
6043         // Units of these are MapBlocks
6044         v3s16 p_min = blockpos_min;
6045         v3s16 p_max = blockpos_max;
6046
6047         VoxelArea block_area_nodes
6048                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6049         
6050         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
6051         if(size_MB >= 1)
6052         {
6053                 dstream<<"initialEmerge: area: ";
6054                 block_area_nodes.print(dstream);
6055                 dstream<<" ("<<size_MB<<"MB)";
6056                 dstream<<std::endl;
6057         }
6058
6059         addArea(block_area_nodes);
6060
6061         for(s32 z=p_min.Z; z<=p_max.Z; z++)
6062         for(s32 y=p_min.Y; y<=p_max.Y; y++)
6063         for(s32 x=p_min.X; x<=p_max.X; x++)
6064         {
6065                 v3s16 p(x,y,z);
6066                 core::map<v3s16, bool>::Node *n;
6067                 n = m_loaded_blocks.find(p);
6068                 if(n != NULL)
6069                         continue;
6070                 
6071                 bool block_data_inexistent = false;
6072                 try
6073                 {
6074                         TimeTaker timer1("emerge load", &emerge_load_time);
6075
6076                         MapBlock *block = m_map->getBlockNoCreate(p);
6077                         if(block->isDummy())
6078                                 block_data_inexistent = true;
6079                         else
6080                                 block->copyTo(*this);
6081                 }
6082                 catch(InvalidPositionException &e)
6083                 {
6084                         block_data_inexistent = true;
6085                 }
6086
6087                 if(block_data_inexistent)
6088                 {
6089                         /*
6090                                 Mark area inexistent
6091                         */
6092                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
6093                         // Fill with VOXELFLAG_INEXISTENT
6094                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
6095                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
6096                         {
6097                                 s32 i = m_area.index(a.MinEdge.X,y,z);
6098                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
6099                         }
6100                 }
6101
6102                 m_loaded_blocks.insert(p, !block_data_inexistent);
6103         }
6104 }
6105
6106 void ManualMapVoxelManipulator::blitBackAll(
6107                 core::map<v3s16, MapBlock*> * modified_blocks)
6108 {
6109         if(m_area.getExtent() == v3s16(0,0,0))
6110                 return;
6111         
6112         /*
6113                 Copy data of all blocks
6114         */
6115         for(core::map<v3s16, bool>::Iterator
6116                         i = m_loaded_blocks.getIterator();
6117                         i.atEnd() == false; i++)
6118         {
6119                 bool existed = i.getNode()->getValue();
6120                 if(existed == false)
6121                         continue;
6122                 v3s16 p = i.getNode()->getKey();
6123                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
6124                 if(block == NULL)
6125                 {
6126                         dstream<<"WARNING: "<<__FUNCTION_NAME
6127                                         <<": got NULL block "
6128                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
6129                                         <<std::endl;
6130                         continue;
6131                 }
6132
6133                 block->copyFrom(*this);
6134
6135                 if(modified_blocks)
6136                         modified_blocks->insert(p, block);
6137         }
6138 }
6139
6140 //END