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