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