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