map generation framework under development... not quite operational at this point.
[oweals/minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "map.h"
21 #include "main.h"
22 #include "jmutexautolock.h"
23 #include "client.h"
24 #include "filesys.h"
25 #include "utility.h"
26 #include "voxel.h"
27 #include "porting.h"
28 #include "mineral.h"
29
30 /*
31         Map
32 */
33
34 Map::Map(std::ostream &dout):
35         m_dout(dout),
36         m_camera_position(0,0,0),
37         m_camera_direction(0,0,1),
38         m_sector_cache(NULL),
39         m_hwrapper(this)
40 {
41         m_sector_mutex.Init();
42         m_camera_mutex.Init();
43         assert(m_sector_mutex.IsInitialized());
44         assert(m_camera_mutex.IsInitialized());
45         
46         // Get this so that the player can stay on it at first
47         //getSector(v2s16(0,0));
48 }
49
50 Map::~Map()
51 {
52         /*
53                 Stop updater thread
54         */
55         /*updater.setRun(false);
56         while(updater.IsRunning())
57                 sleep_s(1);*/
58
59         /*
60                 Free all MapSectors.
61         */
62         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
63         for(; i.atEnd() == false; i++)
64         {
65                 MapSector *sector = i.getNode()->getValue();
66                 delete sector;
67         }
68 }
69
70 MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
71 {
72         if(m_sector_cache != NULL && p == m_sector_cache_p){
73                 MapSector * sector = m_sector_cache;
74                 // Reset inactivity timer
75                 sector->usage_timer = 0.0;
76                 return sector;
77         }
78         
79         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
80         
81         if(n == NULL)
82                 return NULL;
83         
84         MapSector *sector = n->getValue();
85         
86         // Cache the last result
87         m_sector_cache_p = p;
88         m_sector_cache = sector;
89
90         // Reset inactivity timer
91         sector->usage_timer = 0.0;
92         return sector;
93 }
94
95 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
96 {
97         JMutexAutoLock lock(m_sector_mutex);
98
99         return getSectorNoGenerateNoExNoLock(p);
100 }
101
102 MapSector * Map::getSectorNoGenerate(v2s16 p)
103 {
104         MapSector *sector = getSectorNoGenerateNoEx(p);
105         if(sector == NULL)
106                 throw InvalidPositionException();
107         
108         return sector;
109 }
110
111 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
112 {       
113         v2s16 p2d(p3d.X, p3d.Z);
114         MapSector * sector = getSectorNoGenerate(p2d);
115
116         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
117
118         return block;
119 }
120
121 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
122 {
123         try
124         {
125                 v2s16 p2d(p3d.X, p3d.Z);
126                 MapSector * sector = getSectorNoGenerate(p2d);
127                 MapBlock *block = sector->getBlockNoCreate(p3d.Y);
128                 return block;
129         }
130         catch(InvalidPositionException &e)
131         {
132                 return NULL;
133         }
134 }
135
136 f32 Map::getGroundHeight(v2s16 p, bool generate)
137 {
138         try{
139                 v2s16 sectorpos = getNodeSectorPos(p);
140                 MapSector * sref = getSectorNoGenerate(sectorpos);
141                 v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
142                 f32 y = sref->getGroundHeight(relpos);
143                 return y;
144         }
145         catch(InvalidPositionException &e)
146         {
147                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
148         }
149 }
150
151 void Map::setGroundHeight(v2s16 p, f32 y, bool generate)
152 {
153         /*m_dout<<DTIME<<"Map::setGroundHeight(("
154                         <<p.X<<","<<p.Y
155                         <<"), "<<y<<")"<<std::endl;*/
156         v2s16 sectorpos = getNodeSectorPos(p);
157         MapSector * sref = getSectorNoGenerate(sectorpos);
158         v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
159         //sref->mutex.Lock();
160         sref->setGroundHeight(relpos, y);
161         //sref->mutex.Unlock();
162 }
163
164 bool Map::isNodeUnderground(v3s16 p)
165 {
166         v3s16 blockpos = getNodeBlockPos(p);
167         try{
168                 MapBlock * block = getBlockNoCreate(blockpos);
169                 return block->getIsUnderground();
170         }
171         catch(InvalidPositionException &e)
172         {
173                 return false;
174         }
175 }
176
177 /*
178         Goes recursively through the neighbours of the node.
179
180         Alters only transparent nodes.
181
182         If the lighting of the neighbour is lower than the lighting of
183         the node was (before changing it to 0 at the step before), the
184         lighting of the neighbour is set to 0 and then the same stuff
185         repeats for the neighbour.
186
187         The ending nodes of the routine are stored in light_sources.
188         This is useful when a light is removed. In such case, this
189         routine can be called for the light node and then again for
190         light_sources to re-light the area without the removed light.
191
192         values of from_nodes are lighting values.
193 */
194 void Map::unspreadLight(enum LightBank bank,
195                 core::map<v3s16, u8> & from_nodes,
196                 core::map<v3s16, bool> & light_sources,
197                 core::map<v3s16, MapBlock*>  & modified_blocks)
198 {
199         v3s16 dirs[6] = {
200                 v3s16(0,0,1), // back
201                 v3s16(0,1,0), // top
202                 v3s16(1,0,0), // right
203                 v3s16(0,0,-1), // front
204                 v3s16(0,-1,0), // bottom
205                 v3s16(-1,0,0), // left
206         };
207         
208         if(from_nodes.size() == 0)
209                 return;
210         
211         u32 blockchangecount = 0;
212
213         core::map<v3s16, u8> unlighted_nodes;
214         core::map<v3s16, u8>::Iterator j;
215         j = from_nodes.getIterator();
216
217         /*
218                 Initialize block cache
219         */
220         v3s16 blockpos_last;
221         MapBlock *block = NULL;
222         // Cache this a bit, too
223         bool block_checked_in_modified = false;
224         
225         for(; j.atEnd() == false; j++)
226         {
227                 v3s16 pos = j.getNode()->getKey();
228                 v3s16 blockpos = getNodeBlockPos(pos);
229                 
230                 // Only fetch a new block if the block position has changed
231                 try{
232                         if(block == NULL || blockpos != blockpos_last){
233                                 block = getBlockNoCreate(blockpos);
234                                 blockpos_last = blockpos;
235
236                                 block_checked_in_modified = false;
237                                 blockchangecount++;
238                         }
239                 }
240                 catch(InvalidPositionException &e)
241                 {
242                         continue;
243                 }
244
245                 if(block->isDummy())
246                         continue;
247
248                 // Calculate relative position in block
249                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
250
251                 // Get node straight from the block
252                 MapNode n = block->getNode(relpos);
253                 
254                 u8 oldlight = j.getNode()->getValue();
255                 
256                 // Loop through 6 neighbors
257                 for(u16 i=0; i<6; i++)
258                 {
259                         // Get the position of the neighbor node
260                         v3s16 n2pos = pos + dirs[i];
261                         
262                         // Get the block where the node is located
263                         v3s16 blockpos = getNodeBlockPos(n2pos);
264
265                         try
266                         {
267                                 // Only fetch a new block if the block position has changed
268                                 try{
269                                         if(block == NULL || blockpos != blockpos_last){
270                                                 block = getBlockNoCreate(blockpos);
271                                                 blockpos_last = blockpos;
272
273                                                 block_checked_in_modified = false;
274                                                 blockchangecount++;
275                                         }
276                                 }
277                                 catch(InvalidPositionException &e)
278                                 {
279                                         continue;
280                                 }
281                                 
282                                 // Calculate relative position in block
283                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
284                                 // Get node straight from the block
285                                 MapNode n2 = block->getNode(relpos);
286                                 
287                                 bool changed = false;
288
289                                 //TODO: Optimize output by optimizing light_sources?
290
291                                 /*
292                                         If the neighbor is dimmer than what was specified
293                                         as oldlight (the light of the previous node)
294                                 */
295                                 if(n2.getLight(bank) < oldlight)
296                                 {
297                                         /*
298                                                 And the neighbor is transparent and it has some light
299                                         */
300                                         if(n2.light_propagates() && n2.getLight(bank) != 0)
301                                         {
302                                                 /*
303                                                         Set light to 0 and add to queue
304                                                 */
305
306                                                 u8 current_light = n2.getLight(bank);
307                                                 n2.setLight(bank, 0);
308                                                 block->setNode(relpos, n2);
309
310                                                 unlighted_nodes.insert(n2pos, current_light);
311                                                 changed = true;
312
313                                                 /*
314                                                         Remove from light_sources if it is there
315                                                         NOTE: This doesn't happen nearly at all
316                                                 */
317                                                 /*if(light_sources.find(n2pos))
318                                                 {
319                                                         std::cout<<"Removed from light_sources"<<std::endl;
320                                                         light_sources.remove(n2pos);
321                                                 }*/
322                                         }
323                                         
324                                         /*// DEBUG
325                                         if(light_sources.find(n2pos) != NULL)
326                                                 light_sources.remove(n2pos);*/
327                                 }
328                                 else{
329                                         light_sources.insert(n2pos, true);
330                                 }
331
332                                 // Add to modified_blocks
333                                 if(changed == true && block_checked_in_modified == false)
334                                 {
335                                         // If the block is not found in modified_blocks, add.
336                                         if(modified_blocks.find(blockpos) == NULL)
337                                         {
338                                                 modified_blocks.insert(blockpos, block);
339                                         }
340                                         block_checked_in_modified = true;
341                                 }
342                         }
343                         catch(InvalidPositionException &e)
344                         {
345                                 continue;
346                         }
347                 }
348         }
349
350         /*dstream<<"unspreadLight(): Changed block "
351                         <<blockchangecount<<" times"
352                         <<" for "<<from_nodes.size()<<" nodes"
353                         <<std::endl;*/
354         
355         if(unlighted_nodes.size() > 0)
356                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
357 }
358
359 /*
360         A single-node wrapper of the above
361 */
362 void Map::unLightNeighbors(enum LightBank bank,
363                 v3s16 pos, u8 lightwas,
364                 core::map<v3s16, bool> & light_sources,
365                 core::map<v3s16, MapBlock*>  & modified_blocks)
366 {
367         core::map<v3s16, u8> from_nodes;
368         from_nodes.insert(pos, lightwas);
369
370         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
371 }
372
373 /*
374         Lights neighbors of from_nodes, collects all them and then
375         goes on recursively.
376 */
377 void Map::spreadLight(enum LightBank bank,
378                 core::map<v3s16, bool> & from_nodes,
379                 core::map<v3s16, MapBlock*> & modified_blocks)
380 {
381         const v3s16 dirs[6] = {
382                 v3s16(0,0,1), // back
383                 v3s16(0,1,0), // top
384                 v3s16(1,0,0), // right
385                 v3s16(0,0,-1), // front
386                 v3s16(0,-1,0), // bottom
387                 v3s16(-1,0,0), // left
388         };
389
390         if(from_nodes.size() == 0)
391                 return;
392         
393         u32 blockchangecount = 0;
394
395         core::map<v3s16, bool> lighted_nodes;
396         core::map<v3s16, bool>::Iterator j;
397         j = from_nodes.getIterator();
398
399         /*
400                 Initialize block cache
401         */
402         v3s16 blockpos_last;
403         MapBlock *block = NULL;
404         // Cache this a bit, too
405         bool block_checked_in_modified = false;
406         
407         for(; j.atEnd() == false; j++)
408         //for(; j != from_nodes.end(); j++)
409         {
410                 v3s16 pos = j.getNode()->getKey();
411                 //v3s16 pos = *j;
412                 //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
413                 v3s16 blockpos = getNodeBlockPos(pos);
414                 
415                 // Only fetch a new block if the block position has changed
416                 try{
417                         if(block == NULL || blockpos != blockpos_last){
418                                 block = getBlockNoCreate(blockpos);
419                                 blockpos_last = blockpos;
420
421                                 block_checked_in_modified = false;
422                                 blockchangecount++;
423                         }
424                 }
425                 catch(InvalidPositionException &e)
426                 {
427                         continue;
428                 }
429
430                 if(block->isDummy())
431                         continue;
432
433                 // Calculate relative position in block
434                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
435
436                 // Get node straight from the block
437                 MapNode n = block->getNode(relpos);
438
439                 u8 oldlight = n.getLight(bank);
440                 u8 newlight = diminish_light(oldlight);
441
442                 // Loop through 6 neighbors
443                 for(u16 i=0; i<6; i++){
444                         // Get the position of the neighbor node
445                         v3s16 n2pos = pos + dirs[i];
446                         
447                         // Get the block where the node is located
448                         v3s16 blockpos = getNodeBlockPos(n2pos);
449
450                         try
451                         {
452                                 // Only fetch a new block if the block position has changed
453                                 try{
454                                         if(block == NULL || blockpos != blockpos_last){
455                                                 block = getBlockNoCreate(blockpos);
456                                                 blockpos_last = blockpos;
457
458                                                 block_checked_in_modified = false;
459                                                 blockchangecount++;
460                                         }
461                                 }
462                                 catch(InvalidPositionException &e)
463                                 {
464                                         continue;
465                                 }
466                                 
467                                 // Calculate relative position in block
468                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
469                                 // Get node straight from the block
470                                 MapNode n2 = block->getNode(relpos);
471                                 
472                                 bool changed = false;
473                                 /*
474                                         If the neighbor is brighter than the current node,
475                                         add to list (it will light up this node on its turn)
476                                 */
477                                 if(n2.getLight(bank) > undiminish_light(oldlight))
478                                 {
479                                         lighted_nodes.insert(n2pos, true);
480                                         //lighted_nodes.push_back(n2pos);
481                                         changed = true;
482                                 }
483                                 /*
484                                         If the neighbor is dimmer than how much light this node
485                                         would spread on it, add to list
486                                 */
487                                 if(n2.getLight(bank) < newlight)
488                                 {
489                                         if(n2.light_propagates())
490                                         {
491                                                 n2.setLight(bank, newlight);
492                                                 block->setNode(relpos, n2);
493                                                 lighted_nodes.insert(n2pos, true);
494                                                 //lighted_nodes.push_back(n2pos);
495                                                 changed = true;
496                                         }
497                                 }
498
499                                 // Add to modified_blocks
500                                 if(changed == true && block_checked_in_modified == false)
501                                 {
502                                         // If the block is not found in modified_blocks, add.
503                                         if(modified_blocks.find(blockpos) == NULL)
504                                         {
505                                                 modified_blocks.insert(blockpos, block);
506                                         }
507                                         block_checked_in_modified = true;
508                                 }
509                         }
510                         catch(InvalidPositionException &e)
511                         {
512                                 continue;
513                         }
514                 }
515         }
516
517         /*dstream<<"spreadLight(): Changed block "
518                         <<blockchangecount<<" times"
519                         <<" for "<<from_nodes.size()<<" nodes"
520                         <<std::endl;*/
521         
522         if(lighted_nodes.size() > 0)
523                 spreadLight(bank, lighted_nodes, modified_blocks);
524 }
525
526 /*
527         A single-node source variation of the above.
528 */
529 void Map::lightNeighbors(enum LightBank bank,
530                 v3s16 pos,
531                 core::map<v3s16, MapBlock*> & modified_blocks)
532 {
533         core::map<v3s16, bool> from_nodes;
534         from_nodes.insert(pos, true);
535         spreadLight(bank, from_nodes, modified_blocks);
536 }
537
538 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
539 {
540         v3s16 dirs[6] = {
541                 v3s16(0,0,1), // back
542                 v3s16(0,1,0), // top
543                 v3s16(1,0,0), // right
544                 v3s16(0,0,-1), // front
545                 v3s16(0,-1,0), // bottom
546                 v3s16(-1,0,0), // left
547         };
548         
549         u8 brightest_light = 0;
550         v3s16 brightest_pos(0,0,0);
551         bool found_something = false;
552
553         // Loop through 6 neighbors
554         for(u16 i=0; i<6; i++){
555                 // Get the position of the neighbor node
556                 v3s16 n2pos = p + dirs[i];
557                 MapNode n2;
558                 try{
559                         n2 = getNode(n2pos);
560                 }
561                 catch(InvalidPositionException &e)
562                 {
563                         continue;
564                 }
565                 if(n2.getLight(bank) > brightest_light || found_something == false){
566                         brightest_light = n2.getLight(bank);
567                         brightest_pos = n2pos;
568                         found_something = true;
569                 }
570         }
571
572         if(found_something == false)
573                 throw InvalidPositionException();
574                 
575         return brightest_pos;
576 }
577
578 /*
579         Propagates sunlight down from a node.
580         Starting point gets sunlight.
581
582         Returns the lowest y value of where the sunlight went.
583
584         Mud is turned into grass in where the sunlight stops.
585 */
586 s16 Map::propagateSunlight(v3s16 start,
587                 core::map<v3s16, MapBlock*> & modified_blocks)
588 {
589         s16 y = start.Y;
590         for(; ; y--)
591         {
592                 v3s16 pos(start.X, y, start.Z);
593                 
594                 v3s16 blockpos = getNodeBlockPos(pos);
595                 MapBlock *block;
596                 try{
597                         block = getBlockNoCreate(blockpos);
598                 }
599                 catch(InvalidPositionException &e)
600                 {
601                         break;
602                 }
603
604                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
605                 MapNode n = block->getNode(relpos);
606
607                 if(n.sunlight_propagates())
608                 {
609                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
610                         block->setNode(relpos, n);
611
612                         modified_blocks.insert(blockpos, block);
613                 }
614                 else
615                 {
616                         // Turn mud into grass
617                         if(n.d == CONTENT_MUD)
618                         {
619                                 n.d = CONTENT_GRASS;
620                                 block->setNode(relpos, n);
621                                 modified_blocks.insert(blockpos, block);
622                         }
623
624                         // Sunlight goes no further
625                         break;
626                 }
627         }
628         return y + 1;
629 }
630
631 void Map::updateLighting(enum LightBank bank,
632                 core::map<v3s16, MapBlock*> & a_blocks,
633                 core::map<v3s16, MapBlock*> & modified_blocks)
634 {
635         /*m_dout<<DTIME<<"Map::updateLighting(): "
636                         <<a_blocks.size()<<" blocks."<<std::endl;*/
637         
638         //TimeTaker timer("updateLighting");
639         
640         // For debugging
641         //bool debug=true;
642         //u32 count_was = modified_blocks.size();
643         
644         core::map<v3s16, MapBlock*> blocks_to_update;
645
646         core::map<v3s16, bool> light_sources;
647         
648         core::map<v3s16, u8> unlight_from;
649                 
650         core::map<v3s16, MapBlock*>::Iterator i;
651         i = a_blocks.getIterator();
652         for(; i.atEnd() == false; i++)
653         {
654                 MapBlock *block = i.getNode()->getValue();
655                 
656                 for(;;)
657                 {
658                         // Don't bother with dummy blocks.
659                         if(block->isDummy())
660                                 break;
661                 
662                         v3s16 pos = block->getPos();
663                         modified_blocks.insert(pos, block);
664
665                         blocks_to_update.insert(pos, block);
666
667                         /*
668                                 Clear all light from block
669                         */
670                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
671                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
672                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
673                         {
674                                 
675                                 try{
676                                         v3s16 p(x,y,z);
677                                         MapNode n = block->getNode(v3s16(x,y,z));
678                                         u8 oldlight = n.getLight(bank);
679                                         n.setLight(bank, 0);
680                                         block->setNode(v3s16(x,y,z), n);
681                                         
682                                         // Collect borders for unlighting
683                                         if(x==0 || x == MAP_BLOCKSIZE-1
684                                         || y==0 || y == MAP_BLOCKSIZE-1
685                                         || z==0 || z == MAP_BLOCKSIZE-1)
686                                         {
687                                                 v3s16 p_map = p + v3s16(
688                                                                 MAP_BLOCKSIZE*pos.X,
689                                                                 MAP_BLOCKSIZE*pos.Y,
690                                                                 MAP_BLOCKSIZE*pos.Z);
691                                                 unlight_from.insert(p_map, oldlight);
692                                         }
693                                 }
694                                 catch(InvalidPositionException &e)
695                                 {
696                                         /*
697                                                 This would happen when dealing with a
698                                                 dummy block.
699                                         */
700                                         //assert(0);
701                                         dstream<<"updateLighting(): InvalidPositionException"
702                                                         <<std::endl;
703                                 }
704                         }
705                         
706                         if(bank == LIGHTBANK_DAY)
707                         {
708                                 bool bottom_valid = block->propagateSunlight(light_sources);
709
710                                 // If bottom is valid, we're done.
711                                 if(bottom_valid)
712                                         break;
713                         }
714                         else if(bank == LIGHTBANK_NIGHT)
715                         {
716                                 // For night lighting, sunlight is not propagated
717                                 break;
718                         }
719                         else
720                         {
721                                 // Invalid lighting bank
722                                 assert(0);
723                         }
724                                 
725                         /*dstream<<"Bottom for sunlight-propagated block ("
726                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
727                                         <<std::endl;*/
728
729                         // Bottom sunlight is not valid; get the block and loop to it
730
731                         pos.Y--;
732                         try{
733                                 block = getBlockNoCreate(pos);
734                         }
735                         catch(InvalidPositionException &e)
736                         {
737                                 assert(0);
738                         }
739                         
740                 }
741         }
742
743 #if 0
744         {
745                 TimeTaker timer("unspreadLight");
746                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
747         }
748         
749         if(debug)
750         {
751                 u32 diff = modified_blocks.size() - count_was;
752                 count_was = modified_blocks.size();
753                 dstream<<"unspreadLight modified "<<diff<<std::endl;
754         }
755
756         {
757                 TimeTaker timer("spreadLight");
758                 spreadLight(bank, light_sources, modified_blocks);
759         }
760         
761         if(debug)
762         {
763                 u32 diff = modified_blocks.size() - count_was;
764                 count_was = modified_blocks.size();
765                 dstream<<"spreadLight modified "<<diff<<std::endl;
766         }
767 #endif
768         
769         {
770                 //MapVoxelManipulator vmanip(this);
771                 
772                 // Make a manual voxel manipulator and load all the blocks
773                 // that touch the requested blocks
774                 ManualMapVoxelManipulator vmanip(this);
775                 core::map<v3s16, MapBlock*>::Iterator i;
776                 i = blocks_to_update.getIterator();
777                 for(; i.atEnd() == false; i++)
778                 {
779                         MapBlock *block = i.getNode()->getValue();
780                         v3s16 p = block->getPos();
781                         
782                         // Add all surrounding blocks
783                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
784
785                         /*
786                                 Add all surrounding blocks that have up-to-date lighting
787                                 NOTE: This doesn't quite do the job (not everything
788                                       appropriate is lighted)
789                         */
790                         /*for(s16 z=-1; z<=1; z++)
791                         for(s16 y=-1; y<=1; y++)
792                         for(s16 x=-1; x<=1; x++)
793                         {
794                                 v3s16 p(x,y,z);
795                                 MapBlock *block = getBlockNoCreateNoEx(p);
796                                 if(block == NULL)
797                                         continue;
798                                 if(block->isDummy())
799                                         continue;
800                                 if(block->getLightingExpired())
801                                         continue;
802                                 vmanip.initialEmerge(p, p);
803                         }*/
804                         
805                         // Lighting of block will be updated completely
806                         block->setLightingExpired(false);
807                 }
808
809                 {
810                         //TimeTaker timer("unSpreadLight");
811                         vmanip.unspreadLight(bank, unlight_from, light_sources);
812                 }
813                 {
814                         //TimeTaker timer("spreadLight");
815                         vmanip.spreadLight(bank, light_sources);
816                 }
817                 {
818                         //TimeTaker timer("blitBack");
819                         vmanip.blitBack(modified_blocks);
820                 }
821                 /*dstream<<"emerge_time="<<emerge_time<<std::endl;
822                 emerge_time = 0;*/
823         }
824
825         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
826 }
827
828 void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
829                 core::map<v3s16, MapBlock*> & modified_blocks)
830 {
831         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
832         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
833         
834         /*
835                 Update information about whether day and night light differ
836         */
837         for(core::map<v3s16, MapBlock*>::Iterator
838                         i = modified_blocks.getIterator();
839                         i.atEnd() == false; i++)
840         {
841                 MapBlock *block = i.getNode()->getValue();
842                 block->updateDayNightDiff();
843         }
844 }
845
846 /*
847         This is called after changing a node from transparent to opaque.
848         The lighting value of the node should be left as-is after changing
849         other values. This sets the lighting value to 0.
850 */
851 /*void Map::nodeAddedUpdate(v3s16 p, u8 lightwas,
852                 core::map<v3s16, MapBlock*> &modified_blocks)*/
853 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
854                 core::map<v3s16, MapBlock*> &modified_blocks)
855 {
856         /*PrintInfo(m_dout);
857         m_dout<<DTIME<<"Map::nodeAddedUpdate(): p=("
858                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
859
860         /*
861                 From this node to nodes underneath:
862                 If lighting is sunlight (1.0), unlight neighbours and
863                 set lighting to 0.
864                 Else discontinue.
865         */
866
867         v3s16 toppos = p + v3s16(0,1,0);
868         v3s16 bottompos = p + v3s16(0,-1,0);
869
870         bool node_under_sunlight = true;
871         core::map<v3s16, bool> light_sources;
872
873         /*
874                 If there is a node at top and it doesn't have sunlight,
875                 there has not been any sunlight going down.
876
877                 Otherwise there probably is.
878         */
879         try{
880                 MapNode topnode = getNode(toppos);
881
882                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
883                         node_under_sunlight = false;
884         }
885         catch(InvalidPositionException &e)
886         {
887         }
888         
889         if(n.d != CONTENT_TORCH)
890         {
891                 /*
892                         If there is grass below, change it to mud
893                 */
894                 try{
895                         MapNode bottomnode = getNode(bottompos);
896                         
897                         if(bottomnode.d == CONTENT_GRASS
898                                         || bottomnode.d == CONTENT_GRASS_FOOTSTEPS)
899                         {
900                                 bottomnode.d = CONTENT_MUD;
901                                 setNode(bottompos, bottomnode);
902                         }
903                 }
904                 catch(InvalidPositionException &e)
905                 {
906                 }
907         }
908
909         enum LightBank banks[] =
910         {
911                 LIGHTBANK_DAY,
912                 LIGHTBANK_NIGHT
913         };
914         for(s32 i=0; i<2; i++)
915         {
916                 enum LightBank bank = banks[i];
917
918                 u8 lightwas = getNode(p).getLight(bank);
919
920                 // Add the block of the added node to modified_blocks
921                 v3s16 blockpos = getNodeBlockPos(p);
922                 MapBlock * block = getBlockNoCreate(blockpos);
923                 assert(block != NULL);
924                 modified_blocks.insert(blockpos, block);
925                 
926                 if(isValidPosition(p) == false)
927                         throw;
928                         
929                 // Unlight neighbours of node.
930                 // This means setting light of all consequent dimmer nodes
931                 // to 0.
932                 // This also collects the nodes at the border which will spread
933                 // light again into this.
934                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
935
936                 n.setLight(bank, 0);
937         }
938         
939         setNode(p, n);
940         
941         /*
942                 If node is under sunlight, take all sunlighted nodes under
943                 it and clear light from them and from where the light has
944                 been spread.
945                 TODO: This could be optimized by mass-unlighting instead
946                       of looping
947         */
948         if(node_under_sunlight)
949         {
950                 s16 y = p.Y - 1;
951                 for(;; y--){
952                         //m_dout<<DTIME<<"y="<<y<<std::endl;
953                         v3s16 n2pos(p.X, y, p.Z);
954                         
955                         MapNode n2;
956                         try{
957                                 n2 = getNode(n2pos);
958                         }
959                         catch(InvalidPositionException &e)
960                         {
961                                 break;
962                         }
963
964                         if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
965                         {
966                                 //m_dout<<DTIME<<"doing"<<std::endl;
967                                 unLightNeighbors(LIGHTBANK_DAY,
968                                                 n2pos, n2.getLight(LIGHTBANK_DAY),
969                                                 light_sources, modified_blocks);
970                                 n2.setLight(LIGHTBANK_DAY, 0);
971                                 setNode(n2pos, n2);
972                         }
973                         else
974                                 break;
975                 }
976         }
977         
978         for(s32 i=0; i<2; i++)
979         {
980                 enum LightBank bank = banks[i];
981                 
982                 /*
983                         Spread light from all nodes that might be capable of doing so
984                         TODO: Convert to spreadLight
985                 */
986                 spreadLight(bank, light_sources, modified_blocks);
987         }
988
989         /*
990                 Update information about whether day and night light differ
991         */
992         for(core::map<v3s16, MapBlock*>::Iterator
993                         i = modified_blocks.getIterator();
994                         i.atEnd() == false; i++)
995         {
996                 MapBlock *block = i.getNode()->getValue();
997                 block->updateDayNightDiff();
998         }
999
1000         /*
1001                 Add neighboring liquid nodes and the node itself if it is
1002                 liquid (=water node was added) to transform queue.
1003         */
1004         v3s16 dirs[7] = {
1005                 v3s16(0,0,0), // self
1006                 v3s16(0,0,1), // back
1007                 v3s16(0,1,0), // top
1008                 v3s16(1,0,0), // right
1009                 v3s16(0,0,-1), // front
1010                 v3s16(0,-1,0), // bottom
1011                 v3s16(-1,0,0), // left
1012         };
1013         for(u16 i=0; i<7; i++)
1014         {
1015                 try
1016                 {
1017
1018                 v3s16 p2 = p + dirs[i];
1019                 
1020                 MapNode n2 = getNode(p2);
1021                 if(content_liquid(n2.d))
1022                 {
1023                         m_transforming_liquid.push_back(p2);
1024                 }
1025                 
1026                 }catch(InvalidPositionException &e)
1027                 {
1028                 }
1029         }
1030 }
1031
1032 /*
1033 */
1034 void Map::removeNodeAndUpdate(v3s16 p,
1035                 core::map<v3s16, MapBlock*> &modified_blocks)
1036 {
1037         /*PrintInfo(m_dout);
1038         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1039                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1040         
1041         bool node_under_sunlight = true;
1042         
1043         v3s16 toppos = p + v3s16(0,1,0);
1044
1045         // Node will be replaced with this
1046         u8 replace_material = CONTENT_AIR;
1047         
1048         /*
1049                 If there is a node at top and it doesn't have sunlight,
1050                 there will be no sunlight going down.
1051         */
1052         try{
1053                 MapNode topnode = getNode(toppos);
1054
1055                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1056                         node_under_sunlight = false;
1057         }
1058         catch(InvalidPositionException &e)
1059         {
1060         }
1061
1062         core::map<v3s16, bool> light_sources;
1063
1064         enum LightBank banks[] =
1065         {
1066                 LIGHTBANK_DAY,
1067                 LIGHTBANK_NIGHT
1068         };
1069         for(s32 i=0; i<2; i++)
1070         {
1071                 enum LightBank bank = banks[i];
1072         
1073                 /*
1074                         Unlight neighbors (in case the node is a light source)
1075                 */
1076                 unLightNeighbors(bank, p,
1077                                 getNode(p).getLight(bank),
1078                                 light_sources, modified_blocks);
1079         }
1080
1081         /*
1082                 Remove the node.
1083                 This also clears the lighting.
1084         */
1085
1086         MapNode n;
1087         n.d = replace_material;
1088         setNode(p, n);
1089         
1090         for(s32 i=0; i<2; i++)
1091         {
1092                 enum LightBank bank = banks[i];
1093         
1094                 /*
1095                         Recalculate lighting
1096                 */
1097                 spreadLight(bank, light_sources, modified_blocks);
1098         }
1099
1100         // Add the block of the removed node to modified_blocks
1101         v3s16 blockpos = getNodeBlockPos(p);
1102         MapBlock * block = getBlockNoCreate(blockpos);
1103         assert(block != NULL);
1104         modified_blocks.insert(blockpos, block);
1105
1106         /*
1107                 If the removed node was under sunlight, propagate the
1108                 sunlight down from it and then light all neighbors
1109                 of the propagated blocks.
1110         */
1111         if(node_under_sunlight)
1112         {
1113                 s16 ybottom = propagateSunlight(p, modified_blocks);
1114                 /*m_dout<<DTIME<<"Node was under sunlight. "
1115                                 "Propagating sunlight";
1116                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1117                 s16 y = p.Y;
1118                 for(; y >= ybottom; y--)
1119                 {
1120                         v3s16 p2(p.X, y, p.Z);
1121                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1122                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1123                                         <<std::endl;*/
1124                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1125                 }
1126         }
1127         else
1128         {
1129                 // Set the lighting of this node to 0
1130                 // TODO: Is this needed? Lighting is cleared up there already.
1131                 try{
1132                         MapNode n = getNode(p);
1133                         n.setLight(LIGHTBANK_DAY, 0);
1134                         setNode(p, n);
1135                 }
1136                 catch(InvalidPositionException &e)
1137                 {
1138                         throw;
1139                 }
1140         }
1141
1142         for(s32 i=0; i<2; i++)
1143         {
1144                 enum LightBank bank = banks[i];
1145         
1146                 // Get the brightest neighbour node and propagate light from it
1147                 v3s16 n2p = getBrightestNeighbour(bank, p);
1148                 try{
1149                         MapNode n2 = getNode(n2p);
1150                         lightNeighbors(bank, n2p, modified_blocks);
1151                 }
1152                 catch(InvalidPositionException &e)
1153                 {
1154                 }
1155         }
1156
1157         /*
1158                 Update information about whether day and night light differ
1159         */
1160         for(core::map<v3s16, MapBlock*>::Iterator
1161                         i = modified_blocks.getIterator();
1162                         i.atEnd() == false; i++)
1163         {
1164                 MapBlock *block = i.getNode()->getValue();
1165                 block->updateDayNightDiff();
1166         }
1167
1168         /*
1169                 Add neighboring liquid nodes to transform queue.
1170         */
1171         v3s16 dirs[6] = {
1172                 v3s16(0,0,1), // back
1173                 v3s16(0,1,0), // top
1174                 v3s16(1,0,0), // right
1175                 v3s16(0,0,-1), // front
1176                 v3s16(0,-1,0), // bottom
1177                 v3s16(-1,0,0), // left
1178         };
1179         for(u16 i=0; i<6; i++)
1180         {
1181                 try
1182                 {
1183
1184                 v3s16 p2 = p + dirs[i];
1185                 
1186                 MapNode n2 = getNode(p2);
1187                 if(content_liquid(n2.d))
1188                 {
1189                         m_transforming_liquid.push_back(p2);
1190                 }
1191                 
1192                 }catch(InvalidPositionException &e)
1193                 {
1194                 }
1195         }
1196 }
1197
1198 #ifndef SERVER
1199 void Map::expireMeshes(bool only_daynight_diffed)
1200 {
1201         TimeTaker timer("expireMeshes()");
1202
1203         core::map<v2s16, MapSector*>::Iterator si;
1204         si = m_sectors.getIterator();
1205         for(; si.atEnd() == false; si++)
1206         {
1207                 MapSector *sector = si.getNode()->getValue();
1208
1209                 core::list< MapBlock * > sectorblocks;
1210                 sector->getBlocks(sectorblocks);
1211                 
1212                 core::list< MapBlock * >::Iterator i;
1213                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1214                 {
1215                         MapBlock *block = *i;
1216
1217                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
1218                         {
1219                                 continue;
1220                         }
1221                         
1222                         {
1223                                 JMutexAutoLock lock(block->mesh_mutex);
1224                                 if(block->mesh != NULL)
1225                                 {
1226                                         /*block->mesh->drop();
1227                                         block->mesh = NULL;*/
1228                                         block->setMeshExpired(true);
1229                                 }
1230                         }
1231                 }
1232         }
1233 }
1234
1235 void Map::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
1236 {
1237         assert(mapType() == MAPTYPE_CLIENT);
1238
1239         try{
1240                 v3s16 p = blockpos + v3s16(0,0,0);
1241                 MapBlock *b = getBlockNoCreate(p);
1242                 b->updateMesh(daynight_ratio);
1243         }
1244         catch(InvalidPositionException &e){}
1245         // Leading edge
1246         try{
1247                 v3s16 p = blockpos + v3s16(-1,0,0);
1248                 MapBlock *b = getBlockNoCreate(p);
1249                 b->updateMesh(daynight_ratio);
1250         }
1251         catch(InvalidPositionException &e){}
1252         try{
1253                 v3s16 p = blockpos + v3s16(0,-1,0);
1254                 MapBlock *b = getBlockNoCreate(p);
1255                 b->updateMesh(daynight_ratio);
1256         }
1257         catch(InvalidPositionException &e){}
1258         try{
1259                 v3s16 p = blockpos + v3s16(0,0,-1);
1260                 MapBlock *b = getBlockNoCreate(p);
1261                 b->updateMesh(daynight_ratio);
1262         }
1263         catch(InvalidPositionException &e){}
1264         /*// Trailing edge
1265         try{
1266                 v3s16 p = blockpos + v3s16(1,0,0);
1267                 MapBlock *b = getBlockNoCreate(p);
1268                 b->updateMesh(daynight_ratio);
1269         }
1270         catch(InvalidPositionException &e){}
1271         try{
1272                 v3s16 p = blockpos + v3s16(0,1,0);
1273                 MapBlock *b = getBlockNoCreate(p);
1274                 b->updateMesh(daynight_ratio);
1275         }
1276         catch(InvalidPositionException &e){}
1277         try{
1278                 v3s16 p = blockpos + v3s16(0,0,1);
1279                 MapBlock *b = getBlockNoCreate(p);
1280                 b->updateMesh(daynight_ratio);
1281         }
1282         catch(InvalidPositionException &e){}*/
1283 }
1284
1285 #endif
1286
1287 bool Map::dayNightDiffed(v3s16 blockpos)
1288 {
1289         try{
1290                 v3s16 p = blockpos + v3s16(0,0,0);
1291                 MapBlock *b = getBlockNoCreate(p);
1292                 if(b->dayNightDiffed())
1293                         return true;
1294         }
1295         catch(InvalidPositionException &e){}
1296         // Leading edges
1297         try{
1298                 v3s16 p = blockpos + v3s16(-1,0,0);
1299                 MapBlock *b = getBlockNoCreate(p);
1300                 if(b->dayNightDiffed())
1301                         return true;
1302         }
1303         catch(InvalidPositionException &e){}
1304         try{
1305                 v3s16 p = blockpos + v3s16(0,-1,0);
1306                 MapBlock *b = getBlockNoCreate(p);
1307                 if(b->dayNightDiffed())
1308                         return true;
1309         }
1310         catch(InvalidPositionException &e){}
1311         try{
1312                 v3s16 p = blockpos + v3s16(0,0,-1);
1313                 MapBlock *b = getBlockNoCreate(p);
1314                 if(b->dayNightDiffed())
1315                         return true;
1316         }
1317         catch(InvalidPositionException &e){}
1318         // Trailing edges
1319         try{
1320                 v3s16 p = blockpos + v3s16(1,0,0);
1321                 MapBlock *b = getBlockNoCreate(p);
1322                 if(b->dayNightDiffed())
1323                         return true;
1324         }
1325         catch(InvalidPositionException &e){}
1326         try{
1327                 v3s16 p = blockpos + v3s16(0,1,0);
1328                 MapBlock *b = getBlockNoCreate(p);
1329                 if(b->dayNightDiffed())
1330                         return true;
1331         }
1332         catch(InvalidPositionException &e){}
1333         try{
1334                 v3s16 p = blockpos + v3s16(0,0,1);
1335                 MapBlock *b = getBlockNoCreate(p);
1336                 if(b->dayNightDiffed())
1337                         return true;
1338         }
1339         catch(InvalidPositionException &e){}
1340
1341         return false;
1342 }
1343
1344 /*
1345         Updates usage timers
1346 */
1347 void Map::timerUpdate(float dtime)
1348 {
1349         JMutexAutoLock lock(m_sector_mutex);
1350
1351         core::map<v2s16, MapSector*>::Iterator si;
1352
1353         si = m_sectors.getIterator();
1354         for(; si.atEnd() == false; si++)
1355         {
1356                 MapSector *sector = si.getNode()->getValue();
1357                 sector->usage_timer += dtime;
1358         }
1359 }
1360
1361 void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
1362 {
1363         /*
1364                 Wait for caches to be removed before continuing.
1365                 
1366                 This disables the existence of caches while locked
1367         */
1368         //SharedPtr<JMutexAutoLock> cachelock(m_blockcachelock.waitCaches());
1369
1370         core::list<v2s16>::Iterator j;
1371         for(j=list.begin(); j!=list.end(); j++)
1372         {
1373                 MapSector *sector = m_sectors[*j];
1374                 if(only_blocks)
1375                 {
1376                         sector->deleteBlocks();
1377                 }
1378                 else
1379                 {
1380                         /*
1381                                 If sector is in sector cache, remove it from there
1382                         */
1383                         if(m_sector_cache == sector)
1384                         {
1385                                 m_sector_cache = NULL;
1386                         }
1387                         /*
1388                                 Remove from map and delete
1389                         */
1390                         m_sectors.remove(*j);
1391                         delete sector;
1392                 }
1393         }
1394 }
1395
1396 u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
1397                 core::list<v3s16> *deleted_blocks)
1398 {
1399         JMutexAutoLock lock(m_sector_mutex);
1400
1401         core::list<v2s16> sector_deletion_queue;
1402         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
1403         for(; i.atEnd() == false; i++)
1404         {
1405                 MapSector *sector = i.getNode()->getValue();
1406                 /*
1407                         Delete sector from memory if it hasn't been used in a long time
1408                 */
1409                 if(sector->usage_timer > timeout)
1410                 {
1411                         sector_deletion_queue.push_back(i.getNode()->getKey());
1412                         
1413                         if(deleted_blocks != NULL)
1414                         {
1415                                 // Collect positions of blocks of sector
1416                                 MapSector *sector = i.getNode()->getValue();
1417                                 core::list<MapBlock*> blocks;
1418                                 sector->getBlocks(blocks);
1419                                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1420                                                 i != blocks.end(); i++)
1421                                 {
1422                                         deleted_blocks->push_back((*i)->getPos());
1423                                 }
1424                         }
1425                 }
1426         }
1427         deleteSectors(sector_deletion_queue, only_blocks);
1428         return sector_deletion_queue.getSize();
1429 }
1430
1431 void Map::PrintInfo(std::ostream &out)
1432 {
1433         out<<"Map: ";
1434 }
1435
1436 #define WATER_DROP_BOOST 4
1437
1438 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1439 {
1440         DSTACK(__FUNCTION_NAME);
1441         //TimeTaker timer("transformLiquids()");
1442
1443         u32 loopcount = 0;
1444         u32 initial_size = m_transforming_liquid.size();
1445
1446         //dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;
1447
1448         while(m_transforming_liquid.size() != 0)
1449         {
1450                 /*
1451                         Get a queued transforming liquid node
1452                 */
1453                 v3s16 p0 = m_transforming_liquid.pop_front();
1454
1455                 MapNode n0 = getNode(p0);
1456                 
1457                 // Don't deal with non-liquids
1458                 if(content_liquid(n0.d) == false)
1459                         continue;
1460
1461                 bool is_source = !content_flowing_liquid(n0.d);
1462                 
1463                 u8 liquid_level = 8;
1464                 if(is_source == false)
1465                         liquid_level = n0.param2 & 0x0f;
1466                 
1467                 // Turn possible source into non-source
1468                 u8 nonsource_c = make_liquid_flowing(n0.d);
1469
1470                 /*
1471                         If not source, check that some node flows into this one
1472                         and what is the level of liquid in this one
1473                 */
1474                 if(is_source == false)
1475                 {
1476                         s8 new_liquid_level_max = -1;
1477
1478                         v3s16 dirs_from[5] = {
1479                                 v3s16(0,1,0), // top
1480                                 v3s16(0,0,1), // back
1481                                 v3s16(1,0,0), // right
1482                                 v3s16(0,0,-1), // front
1483                                 v3s16(-1,0,0), // left
1484                         };
1485                         for(u16 i=0; i<5; i++)
1486                         {
1487                                 try
1488                                 {
1489
1490                                 bool from_top = (i==0);
1491
1492                                 v3s16 p2 = p0 + dirs_from[i];
1493                                 MapNode n2 = getNode(p2);
1494
1495                                 if(content_liquid(n2.d))
1496                                 {
1497                                         u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1498                                         // Check that the liquids are the same type
1499                                         if(n2_nonsource_c != nonsource_c)
1500                                         {
1501                                                 dstream<<"WARNING: Not handling: different liquids"
1502                                                                 " collide"<<std::endl;
1503                                                 continue;
1504                                         }
1505                                         bool n2_is_source = !content_flowing_liquid(n2.d);
1506                                         s8 n2_liquid_level = 8;
1507                                         if(n2_is_source == false)
1508                                                 n2_liquid_level = n2.param2 & 0x07;
1509                                         
1510                                         s8 new_liquid_level = -1;
1511                                         if(from_top)
1512                                         {
1513                                                 //new_liquid_level = 7;
1514                                                 if(n2_liquid_level >= 7 - WATER_DROP_BOOST)
1515                                                         new_liquid_level = 7;
1516                                                 else
1517                                                         new_liquid_level = n2_liquid_level + WATER_DROP_BOOST;
1518                                         }
1519                                         else if(n2_liquid_level > 0)
1520                                         {
1521                                                 new_liquid_level = n2_liquid_level - 1;
1522                                         }
1523
1524                                         if(new_liquid_level > new_liquid_level_max)
1525                                                 new_liquid_level_max = new_liquid_level;
1526                                 }
1527
1528                                 }catch(InvalidPositionException &e)
1529                                 {
1530                                 }
1531                         } //for
1532                         
1533                         /*
1534                                 If liquid level should be something else, update it and
1535                                 add all the neighboring water nodes to the transform queue.
1536                         */
1537                         if(new_liquid_level_max != liquid_level)
1538                         {
1539                                 if(new_liquid_level_max == -1)
1540                                 {
1541                                         // Remove water alltoghether
1542                                         n0.d = CONTENT_AIR;
1543                                         n0.param2 = 0;
1544                                         setNode(p0, n0);
1545                                 }
1546                                 else
1547                                 {
1548                                         n0.param2 = new_liquid_level_max;
1549                                         setNode(p0, n0);
1550                                 }
1551                                 
1552                                 // Block has been modified
1553                                 {
1554                                         v3s16 blockpos = getNodeBlockPos(p0);
1555                                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1556                                         if(block != NULL)
1557                                                 modified_blocks.insert(blockpos, block);
1558                                 }
1559                                 
1560                                 /*
1561                                         Add neighboring non-source liquid nodes to transform queue.
1562                                 */
1563                                 v3s16 dirs[6] = {
1564                                         v3s16(0,0,1), // back
1565                                         v3s16(0,1,0), // top
1566                                         v3s16(1,0,0), // right
1567                                         v3s16(0,0,-1), // front
1568                                         v3s16(0,-1,0), // bottom
1569                                         v3s16(-1,0,0), // left
1570                                 };
1571                                 for(u16 i=0; i<6; i++)
1572                                 {
1573                                         try
1574                                         {
1575
1576                                         v3s16 p2 = p0 + dirs[i];
1577                                         
1578                                         MapNode n2 = getNode(p2);
1579                                         if(content_flowing_liquid(n2.d))
1580                                         {
1581                                                 m_transforming_liquid.push_back(p2);
1582                                         }
1583                                         
1584                                         }catch(InvalidPositionException &e)
1585                                         {
1586                                         }
1587                                 }
1588                         }
1589                 }
1590                 
1591                 // Get a new one from queue if the node has turned into non-water
1592                 if(content_liquid(n0.d) == false)
1593                         continue;
1594
1595                 /*
1596                         Flow water from this node
1597                 */
1598                 v3s16 dirs_to[5] = {
1599                         v3s16(0,-1,0), // bottom
1600                         v3s16(0,0,1), // back
1601                         v3s16(1,0,0), // right
1602                         v3s16(0,0,-1), // front
1603                         v3s16(-1,0,0), // left
1604                 };
1605                 for(u16 i=0; i<5; i++)
1606                 {
1607                         try
1608                         {
1609
1610                         bool to_bottom = (i == 0);
1611
1612                         // If liquid is at lowest possible height, it's not going
1613                         // anywhere except down
1614                         if(liquid_level == 0 && to_bottom == false)
1615                                 continue;
1616                         
1617                         u8 liquid_next_level = 0;
1618                         // If going to bottom
1619                         if(to_bottom)
1620                         {
1621                                 //liquid_next_level = 7;
1622                                 if(liquid_level >= 7 - WATER_DROP_BOOST)
1623                                         liquid_next_level = 7;
1624                                 else
1625                                         liquid_next_level = liquid_level + WATER_DROP_BOOST;
1626                         }
1627                         else
1628                                 liquid_next_level = liquid_level - 1;
1629
1630                         bool n2_changed = false;
1631                         bool flowed = false;
1632                         
1633                         v3s16 p2 = p0 + dirs_to[i];
1634
1635                         MapNode n2 = getNode(p2);
1636                         //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
1637
1638                         if(content_liquid(n2.d))
1639                         {
1640                                 u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1641                                 // Check that the liquids are the same type
1642                                 if(n2_nonsource_c != nonsource_c)
1643                                 {
1644                                         dstream<<"WARNING: Not handling: different liquids"
1645                                                         " collide"<<std::endl;
1646                                         continue;
1647                                 }
1648                                 bool n2_is_source = !content_flowing_liquid(n2.d);
1649                                 u8 n2_liquid_level = 8;
1650                                 if(n2_is_source == false)
1651                                         n2_liquid_level = n2.param2 & 0x07;
1652                                 
1653                                 if(to_bottom)
1654                                 {
1655                                         flowed = true;
1656                                 }
1657
1658                                 if(n2_is_source)
1659                                 {
1660                                         // Just flow into the source, nothing changes.
1661                                         // n2_changed is not set because destination didn't change
1662                                         flowed = true;
1663                                 }
1664                                 else
1665                                 {
1666                                         if(liquid_next_level > liquid_level)
1667                                         {
1668                                                 n2.param2 = liquid_next_level;
1669                                                 setNode(p2, n2);
1670
1671                                                 n2_changed = true;
1672                                                 flowed = true;
1673                                         }
1674                                 }
1675                         }
1676                         else if(n2.d == CONTENT_AIR)
1677                         {
1678                                 n2.d = nonsource_c;
1679                                 n2.param2 = liquid_next_level;
1680                                 setNode(p2, n2);
1681                                 
1682                                 n2_changed = true;
1683                                 flowed = true;
1684                         }
1685                         
1686                         //dstream<<"[2] n2.param="<<(int)n2.param<<std::endl;
1687
1688                         if(n2_changed)
1689                         {
1690                                 m_transforming_liquid.push_back(p2);
1691                                 
1692                                 v3s16 blockpos = getNodeBlockPos(p2);
1693                                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1694                                 if(block != NULL)
1695                                         modified_blocks.insert(blockpos, block);
1696                         }
1697                         
1698                         // If n2_changed to bottom, don't flow anywhere else
1699                         if(to_bottom && flowed && !is_source)
1700                                 break;
1701                                 
1702                         }catch(InvalidPositionException &e)
1703                         {
1704                         }
1705                 }
1706
1707                 loopcount++;
1708                 //if(loopcount >= 100000)
1709                 if(loopcount >= initial_size * 1)
1710                         break;
1711         }
1712         //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1713 }
1714
1715 /*
1716         ServerMap
1717 */
1718
1719 ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
1720         Map(dout_server),
1721         m_heightmap(NULL)
1722 {
1723         
1724         //m_chunksize = 64;
1725         //m_chunksize = 16;
1726         //m_chunksize = 8;
1727         m_chunksize = 2;
1728
1729         /*
1730                 Experimental and debug stuff
1731         */
1732         
1733         {
1734                 dstream<<"Generating map point attribute lists"<<std::endl;
1735                 
1736                 PointAttributeList *list_baseheight = m_padb.getList("hm_baseheight");
1737                 PointAttributeList *list_randmax = m_padb.getList("hm_randmax");
1738                 PointAttributeList *list_randfactor = m_padb.getList("hm_randfactor");
1739                 PointAttributeList *list_plants_amount = m_padb.getList("plants_amount");
1740                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
1741
1742                 /*
1743                         NOTE: BEWARE: Too big amount of these will make map generation
1744                         slow. Especially those that are read by every block emerge.
1745                         
1746                         Fetch times:
1747                         1000 points: 2-3ms
1748                         5000 points: 15ms
1749                         15000 points: 40ms
1750                 */
1751                 
1752                 for(u32 i=0; i<5000; i++)
1753                 {
1754                         /*u32 lim = MAP_GENERATION_LIMIT;
1755                         if(i < 400)
1756                                 lim = 2000;*/
1757
1758                         u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 5000;
1759
1760                         v3s16 p(
1761                                 -lim + myrand()%(lim*2),
1762                                 0,
1763                                 -lim + myrand()%(lim*2)
1764                         );
1765                         /*float plants_amount = (float)(myrand()%1050) / 1000.0;
1766                         plants_amount = pow(plants_amount, 5);
1767                         list_plants_amount->addPoint(p, Attribute(plants_amount));*/
1768                         
1769                         float plants_amount = 0;
1770                         if(myrand()%4 == 0)
1771                         {
1772                                 plants_amount = 1.5;
1773                         }
1774                         else if(myrand()%4 == 0)
1775                         {
1776                                 plants_amount = 0.5;
1777                         }
1778                         else if(myrand()%2 == 0)
1779                         {
1780                                 plants_amount = 0.03;
1781                         }
1782                         else
1783                         {
1784                                 plants_amount = 0.0;
1785                         }
1786
1787
1788                         list_plants_amount->addPoint(p, Attribute(plants_amount));
1789                 }
1790
1791                 for(u32 i=0; i<1000; i++)
1792                 {
1793                         /*u32 lim = MAP_GENERATION_LIMIT;
1794                         if(i < 400)
1795                                 lim = 2000;*/
1796
1797                         u32 lim = 500 + MAP_GENERATION_LIMIT * i / 1000;
1798
1799                         v3s16 p(
1800                                 -lim + myrand()%(lim*2),
1801                                 0,
1802                                 -lim + myrand()%(lim*2)
1803                         );
1804
1805                         float caves_amount = 0;
1806                         if(myrand()%5 == 0)
1807                         {
1808                                 caves_amount = 1.0;
1809                         }
1810                         else if(myrand()%3 == 0)
1811                         {
1812                                 caves_amount = 0.3;
1813                         }
1814                         else
1815                         {
1816                                 caves_amount = 0.05;
1817                         }
1818
1819                         list_caves_amount->addPoint(p, Attribute(caves_amount));
1820                 }
1821                 
1822                 for(u32 i=0; i<5000; i++)
1823                 {
1824                         /*u32 lim = MAP_GENERATION_LIMIT;
1825                         if(i < 400)
1826                                 lim = 2000;*/
1827
1828                         u32 lim = 1000 + MAP_GENERATION_LIMIT * i / 5000;
1829
1830                         v3s16 p(
1831                                 -lim + (myrand()%(lim*2)),
1832                                 0,
1833                                 -lim + (myrand()%(lim*2))
1834                         );
1835                         
1836                         /*s32 bh_i = (myrand()%200) - 50;
1837                         float baseheight = (float)bh_i;
1838                         
1839                         float m = 100.;
1840                         float e = 3.;
1841                         float randmax = (float)(myrand()%(int)(10.*pow(m, 1./e)))/10.;
1842                         randmax = pow(randmax, e);
1843
1844                         //float randmax = (float)(myrand()%60);
1845                         float randfactor = (float)(myrand()%450) / 1000.0 + 0.4;*/
1846
1847                         float baseheight = 0;
1848                         float randmax = 0;
1849                         float randfactor = 0;
1850
1851                         /*if(myrand()%5 == 0)
1852                         {
1853                                 baseheight = 100;
1854                                 randmax = 50;
1855                                 randfactor = 0.63;
1856                         }
1857                         else if(myrand()%6 == 0)
1858                         {
1859                                 baseheight = 200;
1860                                 randmax = 100;
1861                                 randfactor = 0.66;
1862                         }
1863                         else if(myrand()%4 == 0)
1864                         {
1865                                 baseheight = -3;
1866                                 randmax = 30;
1867                                 randfactor = 0.7;
1868                         }
1869                         else if(myrand()%3 == 0)
1870                         {
1871                                 baseheight = 0;
1872                                 randmax = 30;
1873                                 randfactor = 0.63;
1874                         }
1875                         else
1876                         {
1877                                 baseheight = -3;
1878                                 randmax = 20;
1879                                 randfactor = 0.5;
1880                         }*/
1881                         
1882                         if(myrand()%3 < 2)
1883                         {
1884                                 baseheight = 10;
1885                                 randmax = 30;
1886                                 randfactor = 0.7;
1887                         }
1888                         else
1889                         {
1890                                 baseheight = 0;
1891                                 randmax = 15;
1892                                 randfactor = 0.63;
1893                         }
1894
1895                         list_baseheight->addPoint(p, Attribute(baseheight));
1896                         list_randmax->addPoint(p, Attribute(randmax));
1897                         list_randfactor->addPoint(p, Attribute(randfactor));
1898                 }
1899
1900                 /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(5));
1901                 list_randmax->addPoint(v3s16(0,0,0), Attribute(20));
1902                 list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.6));*/
1903
1904                 // Easy spawn point
1905                 /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(0));
1906                 list_randmax->addPoint(v3s16(0,0,0), Attribute(10));
1907                 list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.65));*/
1908         }
1909         
1910         /*
1911                 Try to load map; if not found, create a new one.
1912         */
1913
1914         m_savedir = savedir;
1915         m_map_saving_enabled = false;
1916         
1917         try
1918         {
1919                 // If directory exists, check contents and load if possible
1920                 if(fs::PathExists(m_savedir))
1921                 {
1922                         // If directory is empty, it is safe to save into it.
1923                         if(fs::GetDirListing(m_savedir).size() == 0)
1924                         {
1925                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1926                                                 <<std::endl;
1927                                 m_map_saving_enabled = true;
1928                         }
1929                         else
1930                         {
1931                                 // Load master heightmap
1932                                 loadMasterHeightmap();
1933                                 
1934                                 // Load sector (0,0) and throw and exception on fail
1935                                 if(loadSectorFull(v2s16(0,0)) == false)
1936                                         throw LoadError("Failed to load sector (0,0)");
1937
1938                                 dstream<<DTIME<<"Server: Successfully loaded master "
1939                                                 "heightmap and sector (0,0) from "<<savedir<<
1940                                                 ", assuming valid save directory."
1941                                                 <<std::endl;
1942
1943                                 m_map_saving_enabled = true;
1944                                 // Map loaded, not creating new one
1945                                 return;
1946                         }
1947                 }
1948                 // If directory doesn't exist, it is safe to save to it
1949                 else{
1950                         m_map_saving_enabled = true;
1951                 }
1952         }
1953         catch(std::exception &e)
1954         {
1955                 dstream<<DTIME<<"Server: Failed to load map from "<<savedir
1956                                 <<", exception: "<<e.what()<<std::endl;
1957                 dstream<<DTIME<<"Please remove the map or fix it."<<std::endl;
1958                 dstream<<DTIME<<"WARNING: Map saving will be disabled."<<std::endl;
1959         }
1960
1961         dstream<<DTIME<<"Initializing new map."<<std::endl;
1962         
1963         // Create master heightmap
1964         m_heightmap = new UnlimitedHeightmap
1965                         (32, &m_padb);
1966         
1967         // Set map parameters
1968         m_params = mp;
1969         
1970         // Create zero sector
1971         emergeSector(v2s16(0,0));
1972
1973         // Initially write whole map
1974         save(false);
1975 }
1976
1977 ServerMap::~ServerMap()
1978 {
1979         try
1980         {
1981                 if(m_map_saving_enabled)
1982                 {
1983                         //save(false);
1984                         // Save only changed parts
1985                         save(true);
1986                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1987                 }
1988                 else
1989                 {
1990                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1991                 }
1992         }
1993         catch(std::exception &e)
1994         {
1995                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1996                                 <<", exception: "<<e.what()<<std::endl;
1997         }
1998         
1999         if(m_heightmap != NULL)
2000                 delete m_heightmap;
2001         
2002         /*
2003                 Free all MapChunks
2004         */
2005         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2006         for(; i.atEnd() == false; i++)
2007         {
2008                 MapChunk *chunk = i.getNode()->getValue();
2009                 delete chunk;
2010         }
2011 }
2012
2013 MapChunk* ServerMap::generateChunkRaw(v2s16 chunkpos)
2014 {
2015         // Return if chunk already exists
2016         MapChunk *chunk = getChunk(chunkpos);
2017         if(chunk)
2018                 return chunk;
2019         
2020         /*
2021                 Add all sectors
2022         */
2023
2024         dstream<<"generateChunkRaw(): "
2025                         <<"("<<chunkpos.X<<","<<chunkpos.Y<<")"
2026                         <<std::endl;
2027         
2028         TimeTaker timer("generateChunkRaw()");
2029
2030         v2s16 sectorpos_base = chunk_to_sector(chunkpos);
2031
2032         core::map<v3s16, MapBlock*> changed_blocks;
2033         core::map<v3s16, MapBlock*> lighting_invalidated_blocks;
2034
2035         u32 generated_block_count = 0;
2036
2037         for(s16 y=0; y<m_chunksize; y++)
2038         {
2039                 /*dstream<<"Generating sectors "
2040                                 <<"("<<sectorpos_base.X<<"..."
2041                                 <<(sectorpos_base.X+m_chunksize-1)
2042                                 <<", "<<y<<")"
2043                                 <<std::endl;*/
2044                 
2045                 // With caves_amount attribute fetch: ~90ms (379ms peaks)
2046                 // Without: ~38ms (396ms peaks)
2047                 //TimeTaker timer("Chunk sector row");
2048
2049                 for(s16 x=0; x<m_chunksize; x++)
2050                 {
2051                         v2s16 sectorpos = sectorpos_base + v2s16(x,y);
2052
2053                         /*dstream<<"Generating sector "
2054                                         <<"("<<sectorpos.X<<","<<sectorpos.Y<<")"
2055                                         <<std::endl;*/
2056
2057                         // Generate sector
2058                         ServerMapSector *sector = generateSector(sectorpos);
2059
2060                         /*
2061                                 Generate main blocks of sector
2062                         */
2063                         s16 d = 8;
2064                         for(s16 y2=-d/2; y2<d/2; y2++)
2065                         {
2066                                 v3s16 p(x,y2,y);
2067                                 
2068                                 // Check that the block doesn't exist already
2069                                 if(sector->getBlockNoCreateNoEx(y2))
2070                                         continue;
2071                                 
2072                                 generateBlock(p, NULL, sector, changed_blocks,
2073                                                 lighting_invalidated_blocks);
2074
2075                                 generated_block_count++;
2076                         }
2077                 }
2078         }
2079
2080         dstream<<"generateChunkRaw generated "<<generated_block_count
2081                         <<" blocks"<<std::endl;
2082
2083         {
2084                 TimeTaker timer2("generateChunkRaw() lighting");
2085                 // Update lighting
2086                 core::map<v3s16, MapBlock*> lighting_modified_blocks;
2087                 updateLighting(lighting_invalidated_blocks, lighting_modified_blocks);
2088         }
2089         
2090         // Add chunk meta information
2091         chunk = new MapChunk();
2092         m_chunks.insert(chunkpos, chunk);
2093         return chunk;
2094 }
2095
2096 MapChunk* ServerMap::generateChunk(v2s16 chunkpos)
2097 {
2098         /*
2099                 Generate chunk and neighbors
2100         */
2101         for(s16 x=-1; x<=1; x++)
2102         for(s16 y=-1; y<=1; y++)
2103         {
2104                 generateChunkRaw(chunkpos + v2s16(x,y));
2105         }
2106
2107         /*
2108                 Get chunk
2109         */
2110         MapChunk *chunk = getChunk(chunkpos);
2111         assert(chunk);
2112         // Set non-volatile
2113         chunk->setIsVolatile(false);
2114         // Return it
2115         return chunk;
2116 }
2117
2118 ServerMapSector * ServerMap::generateSector(v2s16 p2d)
2119 {
2120         DSTACK("%s: p2d=(%d,%d)",
2121                         __FUNCTION_NAME,
2122                         p2d.X, p2d.Y);
2123         
2124         // Check that it doesn't exist already
2125         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2126         if(sector != NULL)
2127                 return sector;
2128         
2129         /*
2130                 If there is no master heightmap, throw.
2131         */
2132         if(m_heightmap == NULL)
2133         {
2134                 throw InvalidPositionException("emergeSector(): no heightmap");
2135         }
2136
2137         /*
2138                 Do not generate over-limit
2139         */
2140         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2141         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2142         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2143         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2144                 throw InvalidPositionException("emergeSector(): pos. over limit");
2145
2146         /*
2147                 Generate sector and heightmaps
2148         */
2149         
2150         // Number of heightmaps in sector in each direction
2151         u16 hm_split = SECTOR_HEIGHTMAP_SPLIT;
2152
2153         // Heightmap side width
2154         s16 hm_d = MAP_BLOCKSIZE / hm_split;
2155
2156         sector = new ServerMapSector(this, p2d, hm_split);
2157         
2158         // Sector position on map in nodes
2159         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2160
2161         /*dstream<<"Generating sector ("<<p2d.X<<","<<p2d.Y<<")"
2162                         " heightmaps and objects"<<std::endl;*/
2163         
2164         /*
2165                 Calculate some information about local properties
2166         */
2167         
2168         v2s16 mhm_p = p2d * hm_split;
2169         f32 corners[4] = {
2170                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)*hm_split),
2171                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)*hm_split),
2172                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)*hm_split),
2173                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)*hm_split),
2174         };
2175         
2176         float avgheight = (corners[0]+corners[1]+corners[2]+corners[3])/4.0;
2177         float avgslope = 0.0;
2178         avgslope += fabs(avgheight - corners[0]);
2179         avgslope += fabs(avgheight - corners[1]);
2180         avgslope += fabs(avgheight - corners[2]);
2181         avgslope += fabs(avgheight - corners[3]);
2182         avgslope /= 4.0;
2183         avgslope /= MAP_BLOCKSIZE;
2184         //dstream<<"avgslope="<<avgslope<<std::endl;
2185
2186         float pitness = 0.0;
2187         v2f32 a;
2188         a = m_heightmap->getSlope(p2d+v2s16(0,0));
2189         pitness += -a.X;
2190         pitness += -a.Y;
2191         a = m_heightmap->getSlope(p2d+v2s16(0,1));
2192         pitness += -a.X;
2193         pitness += a.Y;
2194         a = m_heightmap->getSlope(p2d+v2s16(1,1));
2195         pitness += a.X;
2196         pitness += a.Y;
2197         a = m_heightmap->getSlope(p2d+v2s16(1,0));
2198         pitness += a.X;
2199         pitness += -a.Y;
2200         pitness /= 4.0;
2201         pitness /= MAP_BLOCKSIZE;
2202         //dstream<<"pitness="<<pitness<<std::endl;
2203
2204         /*
2205                 Get local attributes
2206         */
2207         
2208         float local_plants_amount = 0.5;
2209         
2210 #if 0
2211         {
2212                 //dstream<<"emergeSector(): Reading point attribute lists"<<std::endl;
2213                 //TimeTaker attrtimer("emergeSector() attribute fetch");
2214                 
2215                 // Get plant amount from attributes
2216                 PointAttributeList *palist = m_padb.getList("plants_amount");
2217                 assert(palist);
2218                 /*local_plants_amount =
2219                                 palist->getNearAttr(nodepos2d).getFloat();*/
2220                 local_plants_amount =
2221                                 palist->getInterpolatedFloat(nodepos2d);
2222         }
2223 #endif
2224
2225         /*
2226                 Generate sector heightmap
2227         */
2228
2229         // Loop through sub-heightmaps
2230         for(s16 y=0; y<hm_split; y++)
2231         for(s16 x=0; x<hm_split; x++)
2232         {
2233                 v2s16 p_in_sector = v2s16(x,y);
2234                 v2s16 mhm_p = p2d * hm_split + p_in_sector;
2235                 f32 corners[4] = {
2236                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)),
2237                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)),
2238                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)),
2239                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)),
2240                 };
2241
2242                 /*dstream<<"p_in_sector=("<<p_in_sector.X<<","<<p_in_sector.Y<<")"
2243                                 <<" mhm_p=("<<mhm_p.X<<","<<mhm_p.Y<<")"
2244                                 <<std::endl;*/
2245
2246                 FixedHeightmap *hm = new FixedHeightmap(&m_hwrapper,
2247                                 mhm_p, hm_d);
2248                 sector->setHeightmap(p_in_sector, hm);
2249
2250                 //TODO: Make these values configurable
2251                 //hm->generateContinued(0.0, 0.0, corners);
2252                 //hm->generateContinued(0.25, 0.2, corners);
2253                 //hm->generateContinued(0.5, 0.2, corners);
2254                 //hm->generateContinued(1.0, 0.2, corners);
2255                 //hm->generateContinued(2.0, 0.2, corners);
2256                 //hm->generateContinued(2.0 * avgslope, 0.5, corners);
2257                 hm->generateContinued(avgslope * MAP_BLOCKSIZE/8, 0.5, corners);
2258
2259                 //hm->print();
2260         }
2261
2262         /*
2263                 Generate objects
2264         */
2265         
2266         core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
2267         sector->setObjects(objects);
2268
2269         float area = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
2270
2271         /*
2272                 Plant some trees if there is not much slope
2273         */
2274         {
2275                 // Avgslope is the derivative of a hill
2276                 //float t = avgslope * avgslope;
2277                 float t = avgslope;
2278                 float a = area/16 * m_params.plants_amount * local_plants_amount;
2279                 u32 tree_max;
2280                 //float something = 0.17*0.17;
2281                 float something = 0.3;
2282                 if(t > something)
2283                         tree_max = a / (t/something);
2284                 else
2285                         tree_max = a;
2286                 
2287                 u32 count = (myrand()%(tree_max+1));
2288                 //u32 count = tree_max;
2289                 for(u32 i=0; i<count; i++)
2290                 {
2291                         s16 x = (myrand()%(MAP_BLOCKSIZE-2))+1;
2292                         s16 z = (myrand()%(MAP_BLOCKSIZE-2))+1;
2293                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
2294                         if(y < WATER_LEVEL)
2295                                 continue;
2296                         objects->insert(v3s16(x, y, z),
2297                                         SECTOR_OBJECT_TREE_1);
2298                 }
2299         }
2300         /*
2301                 Plant some bushes if sector is pit-like
2302         */
2303         {
2304                 // Pitness usually goes at around -0.5...0.5
2305                 u32 bush_max = 0;
2306                 u32 a = area/16 * 3.0 * m_params.plants_amount * local_plants_amount;
2307                 if(pitness > 0)
2308                         bush_max = (pitness*a*4);
2309                 if(bush_max > a)
2310                         bush_max = a;
2311                 u32 count = (myrand()%(bush_max+1));
2312                 for(u32 i=0; i<count; i++)
2313                 {
2314                         s16 x = myrand()%(MAP_BLOCKSIZE-0)+0;
2315                         s16 z = myrand()%(MAP_BLOCKSIZE-0)+0;
2316                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
2317                         if(y < WATER_LEVEL)
2318                                 continue;
2319                         objects->insert(v3s16(x, y, z),
2320                                         SECTOR_OBJECT_BUSH_1);
2321                 }
2322         }
2323         /*
2324                 Add ravine (randomly)
2325         */
2326         if(m_params.ravines_amount > 0.001)
2327         {
2328                 if(myrand()%(s32)(200.0 / m_params.ravines_amount) == 0)
2329                 {
2330                         s16 s = 6;
2331                         s16 x = myrand()%(MAP_BLOCKSIZE-s*2-1)+s;
2332                         s16 z = myrand()%(MAP_BLOCKSIZE-s*2-1)+s;
2333                         /*s16 x = 8;
2334                         s16 z = 8;*/
2335                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
2336                         objects->insert(v3s16(x, y, z),
2337                                         SECTOR_OBJECT_RAVINE);
2338                 }
2339         }
2340
2341         /*
2342                 Insert to container
2343         */
2344         m_sectors.insert(p2d, sector);
2345         
2346         return sector;
2347 }
2348
2349 MapSector * ServerMap::emergeSector(v2s16 p2d)
2350 {
2351         DSTACK("%s: p2d=(%d,%d)",
2352                         __FUNCTION_NAME,
2353                         p2d.X, p2d.Y);
2354         
2355         /*
2356                 Check if it exists already in memory
2357         */
2358         MapSector *sector = getSectorNoGenerateNoEx(p2d);
2359         if(sector != NULL)
2360                 return sector;
2361         
2362         /*
2363                 Try to load it from disk
2364         */
2365         if(loadSectorFull(p2d) == true)
2366         {
2367                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
2368                 if(sector == NULL)
2369                 {
2370                         dstream<<"ServerMap::emergeSector(): loadSectorFull didn't make a sector"<<std::endl;
2371                         throw InvalidPositionException("");
2372                 }
2373                 return sector;
2374         }
2375
2376         /*
2377                 Check chunk status
2378         */
2379         v2s16 chunkpos = sector_to_chunk(p2d);
2380         bool chunk_exists = false;
2381         MapChunk *chunk = getChunk(chunkpos);
2382         if(chunk && chunk->getIsVolatile() == false)
2383                 chunk_exists = true;
2384
2385         /*
2386                 If chunk is not generated, generate chunk
2387         */
2388         if(chunk_exists == false)
2389         {
2390                 // Generate chunk and neighbors
2391                 generateChunk(chunkpos);
2392         }
2393         
2394         /*
2395                 Return sector if it exists now
2396         */
2397         sector = getSectorNoGenerateNoEx(p2d);
2398         if(sector != NULL)
2399                 return sector;
2400         
2401         /*
2402                 generateChunk should have generated the sector
2403         */
2404         assert(0);
2405
2406         /*
2407                 Generate directly
2408         */
2409         //return generateSector();
2410 }
2411
2412 MapBlock * ServerMap::generateBlock(
2413                 v3s16 p,
2414                 MapBlock *original_dummy,
2415                 ServerMapSector *sector,
2416                 core::map<v3s16, MapBlock*> &changed_blocks,
2417                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
2418 )
2419 {
2420         DSTACK("%s: p=(%d,%d,%d)",
2421                         __FUNCTION_NAME,
2422                         p.X, p.Y, p.Z);
2423         
2424         /*dstream<<"generateBlock(): "
2425                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2426                         <<std::endl;*/
2427         
2428         MapBlock *block = original_dummy;
2429                         
2430         v2s16 p2d(p.X, p.Z);
2431         s16 block_y = p.Y;
2432         
2433         /*
2434                 Do not generate over-limit
2435         */
2436         if(blockpos_over_limit(p))
2437         {
2438                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2439                 throw InvalidPositionException("generateBlock(): pos. over limit");
2440         }
2441
2442         /*
2443                 If block doesn't exist, create one.
2444                 If it exists, it is a dummy. In that case unDummify() it.
2445
2446                 NOTE: This already sets the map as the parent of the block
2447         */
2448         if(block == NULL)
2449         {
2450                 block = sector->createBlankBlockNoInsert(block_y);
2451         }
2452         else
2453         {
2454                 // Remove the block so that nobody can get a half-generated one.
2455                 sector->removeBlock(block);
2456                 // Allocate the block to contain the generated data
2457                 block->unDummify();
2458         }
2459         
2460         /*u8 water_material = CONTENT_WATER;
2461         if(g_settings.getBool("endless_water"))
2462                 water_material = CONTENT_WATERSOURCE;*/
2463         u8 water_material = CONTENT_WATERSOURCE;
2464         
2465         s32 lowest_ground_y = 32767;
2466         s32 highest_ground_y = -32768;
2467         
2468         // DEBUG
2469         //sector->printHeightmaps();
2470
2471         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2472         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2473         {
2474                 //dstream<<"generateBlock: x0="<<x0<<", z0="<<z0<<std::endl;
2475
2476                 float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
2477                 //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
2478                 if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE)
2479                 {
2480                         dstream<<"WARNING: Surface height not found in sector "
2481                                         "for block that is being emerged"<<std::endl;
2482                         surface_y_f = 0.0;
2483                 }
2484
2485                 s16 surface_y = surface_y_f;
2486                 //avg_ground_y += surface_y;
2487                 if(surface_y < lowest_ground_y)
2488                         lowest_ground_y = surface_y;
2489                 if(surface_y > highest_ground_y)
2490                         highest_ground_y = surface_y;
2491
2492                 s32 surface_depth = 0;
2493                 
2494                 float slope = sector->getSlope(v2s16(x0,z0)).getLength();
2495                 
2496                 //float min_slope = 0.45;
2497                 //float max_slope = 0.85;
2498                 float min_slope = 0.60;
2499                 float max_slope = 1.20;
2500                 float min_slope_depth = 5.0;
2501                 float max_slope_depth = 0;
2502
2503                 if(slope < min_slope)
2504                         surface_depth = min_slope_depth;
2505                 else if(slope > max_slope)
2506                         surface_depth = max_slope_depth;
2507                 else
2508                         surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
2509
2510                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2511                 {
2512                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
2513                         MapNode n;
2514                         /*
2515                                 Calculate lighting
2516                                 
2517                                 NOTE: If there are some man-made structures above the
2518                                 newly created block, they won't be taken into account.
2519                         */
2520                         if(real_y > surface_y)
2521                                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
2522
2523                         /*
2524                                 Calculate material
2525                         */
2526
2527                         // If node is over heightmap y, it's air or water
2528                         if(real_y > surface_y)
2529                         {
2530                                 // If under water level, it's water
2531                                 if(real_y < WATER_LEVEL)
2532                                 {
2533                                         n.d = water_material;
2534                                         n.setLight(LIGHTBANK_DAY,
2535                                                         diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
2536                                         /*
2537                                                 Add to transforming liquid queue (in case it'd
2538                                                 start flowing)
2539                                         */
2540                                         v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
2541                                         m_transforming_liquid.push_back(real_pos);
2542                                 }
2543                                 // else air
2544                                 else
2545                                         n.d = CONTENT_AIR;
2546                         }
2547                         // Else it's ground or dungeons (air)
2548                         else
2549                         {
2550                                 // If it's surface_depth under ground, it's stone
2551                                 if(real_y <= surface_y - surface_depth)
2552                                 {
2553                                         n.d = CONTENT_STONE;
2554                                 }
2555                                 else
2556                                 {
2557                                         // It is mud if it is under the first ground
2558                                         // level or under water
2559                                         if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
2560                                         {
2561                                                 n.d = CONTENT_MUD;
2562                                         }
2563                                         else
2564                                         {
2565                                                 n.d = CONTENT_GRASS;
2566                                         }
2567
2568                                         //n.d = CONTENT_MUD;
2569                                         
2570                                         /*// If under water level, it's mud
2571                                         if(real_y < WATER_LEVEL)
2572                                                 n.d = CONTENT_MUD;
2573                                         // Only the topmost node is grass
2574                                         else if(real_y <= surface_y - 1)
2575                                                 n.d = CONTENT_MUD;
2576                                         else
2577                                                 n.d = CONTENT_GRASS;*/
2578                                 }
2579                         }
2580
2581                         block->setNode(v3s16(x0,y0,z0), n);
2582                 }
2583         }
2584         
2585         /*
2586                 Calculate some helper variables
2587         */
2588         
2589         // Completely underground if the highest part of block is under lowest
2590         // ground height.
2591         // This has to be very sure; it's probably one too strict now but
2592         // that's just better.
2593         bool completely_underground =
2594                         block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y;
2595
2596         bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
2597
2598         bool mostly_underwater_surface = false;
2599         if(highest_ground_y < WATER_LEVEL
2600                         && some_part_underground && !completely_underground)
2601                 mostly_underwater_surface = true;
2602
2603         /*
2604                 Get local attributes
2605         */
2606
2607         //dstream<<"generateBlock(): Getting local attributes"<<std::endl;
2608
2609         float caves_amount = 0.5;
2610
2611 #if 0
2612         {
2613                 /*
2614                         NOTE: BEWARE: Too big amount of attribute points slows verything
2615                         down by a lot.
2616                         1 interpolation from 5000 points takes 2-3ms.
2617                 */
2618                 //TimeTaker timer("generateBlock() local attribute retrieval");
2619                 v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2620                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
2621                 caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
2622         }
2623 #endif
2624
2625         //dstream<<"generateBlock(): Done"<<std::endl;
2626
2627         /*
2628                 Generate dungeons
2629         */
2630
2631         // Initialize temporary table
2632         const s32 ued = MAP_BLOCKSIZE;
2633         bool underground_emptiness[ued*ued*ued];
2634         for(s32 i=0; i<ued*ued*ued; i++)
2635         {
2636                 underground_emptiness[i] = 0;
2637         }
2638         
2639         // Fill table
2640 #if 1
2641         {
2642                 /*
2643                         Initialize orp and ors. Try to find if some neighboring
2644                         MapBlock has a tunnel ended in its side
2645                 */
2646
2647                 v3f orp(
2648                         (float)(myrand()%ued)+0.5,
2649                         (float)(myrand()%ued)+0.5,
2650                         (float)(myrand()%ued)+0.5
2651                 );
2652                 
2653                 bool found_existing = false;
2654
2655                 // Check z-
2656                 try
2657                 {
2658                         s16 z = -1;
2659                         for(s16 y=0; y<ued; y++)
2660                         for(s16 x=0; x<ued; x++)
2661                         {
2662                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2663                                 if(getNode(ap).d == CONTENT_AIR)
2664                                 {
2665                                         orp = v3f(x+1,y+1,0);
2666                                         found_existing = true;
2667                                         goto continue_generating;
2668                                 }
2669                         }
2670                 }
2671                 catch(InvalidPositionException &e){}
2672                 
2673                 // Check z+
2674                 try
2675                 {
2676                         s16 z = ued;
2677                         for(s16 y=0; y<ued; y++)
2678                         for(s16 x=0; x<ued; x++)
2679                         {
2680                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2681                                 if(getNode(ap).d == CONTENT_AIR)
2682                                 {
2683                                         orp = v3f(x+1,y+1,ued-1);
2684                                         found_existing = true;
2685                                         goto continue_generating;
2686                                 }
2687                         }
2688                 }
2689                 catch(InvalidPositionException &e){}
2690                 
2691                 // Check x-
2692                 try
2693                 {
2694                         s16 x = -1;
2695                         for(s16 y=0; y<ued; y++)
2696                         for(s16 z=0; z<ued; z++)
2697                         {
2698                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2699                                 if(getNode(ap).d == CONTENT_AIR)
2700                                 {
2701                                         orp = v3f(0,y+1,z+1);
2702                                         found_existing = true;
2703                                         goto continue_generating;
2704                                 }
2705                         }
2706                 }
2707                 catch(InvalidPositionException &e){}
2708                 
2709                 // Check x+
2710                 try
2711                 {
2712                         s16 x = ued;
2713                         for(s16 y=0; y<ued; y++)
2714                         for(s16 z=0; z<ued; z++)
2715                         {
2716                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2717                                 if(getNode(ap).d == CONTENT_AIR)
2718                                 {
2719                                         orp = v3f(ued-1,y+1,z+1);
2720                                         found_existing = true;
2721                                         goto continue_generating;
2722                                 }
2723                         }
2724                 }
2725                 catch(InvalidPositionException &e){}
2726
2727                 // Check y-
2728                 try
2729                 {
2730                         s16 y = -1;
2731                         for(s16 x=0; x<ued; x++)
2732                         for(s16 z=0; z<ued; z++)
2733                         {
2734                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2735                                 if(getNode(ap).d == CONTENT_AIR)
2736                                 {
2737                                         orp = v3f(x+1,0,z+1);
2738                                         found_existing = true;
2739                                         goto continue_generating;
2740                                 }
2741                         }
2742                 }
2743                 catch(InvalidPositionException &e){}
2744                 
2745                 // Check y+
2746                 try
2747                 {
2748                         s16 y = ued;
2749                         for(s16 x=0; x<ued; x++)
2750                         for(s16 z=0; z<ued; z++)
2751                         {
2752                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2753                                 if(getNode(ap).d == CONTENT_AIR)
2754                                 {
2755                                         orp = v3f(x+1,ued-1,z+1);
2756                                         found_existing = true;
2757                                         goto continue_generating;
2758                                 }
2759                         }
2760                 }
2761                 catch(InvalidPositionException &e){}
2762
2763 continue_generating:
2764                 
2765                 /*
2766                         Choose whether to actually generate dungeon
2767                 */
2768                 bool do_generate_dungeons = true;
2769                 // Don't generate if no part is underground
2770                 if(!some_part_underground)
2771                 {
2772                         do_generate_dungeons = false;
2773                 }
2774                 // Don't generate if mostly underwater surface
2775                 /*else if(mostly_underwater_surface)
2776                 {
2777                         do_generate_dungeons = false;
2778                 }*/
2779                 // Partly underground = cave
2780                 else if(!completely_underground)
2781                 {
2782                         do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
2783                 }
2784                 // Found existing dungeon underground
2785                 else if(found_existing && completely_underground)
2786                 {
2787                         do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
2788                 }
2789                 // Underground and no dungeons found
2790                 else
2791                 {
2792                         do_generate_dungeons = (rand() % 300 <= (s32)(caves_amount*100));
2793                 }
2794
2795                 if(do_generate_dungeons)
2796                 {
2797                         /*
2798                                 Generate some tunnel starting from orp and ors
2799                         */
2800                         for(u16 i=0; i<3; i++)
2801                         {
2802                                 v3f rp(
2803                                         (float)(myrand()%ued)+0.5,
2804                                         (float)(myrand()%ued)+0.5,
2805                                         (float)(myrand()%ued)+0.5
2806                                 );
2807                                 s16 min_d = 0;
2808                                 s16 max_d = 4;
2809                                 s16 rs = (myrand()%(max_d-min_d+1))+min_d;
2810                                 
2811                                 v3f vec = rp - orp;
2812
2813                                 for(float f=0; f<1.0; f+=0.04)
2814                                 {
2815                                         v3f fp = orp + vec * f;
2816                                         v3s16 cp(fp.X, fp.Y, fp.Z);
2817                                         s16 d0 = -rs/2;
2818                                         s16 d1 = d0 + rs - 1;
2819                                         for(s16 z0=d0; z0<=d1; z0++)
2820                                         {
2821                                                 s16 si = rs - abs(z0);
2822                                                 for(s16 x0=-si; x0<=si-1; x0++)
2823                                                 {
2824                                                         s16 si2 = rs - abs(x0);
2825                                                         for(s16 y0=-si2+1; y0<=si2-1; y0++)
2826                                                         {
2827                                                                 s16 z = cp.Z + z0;
2828                                                                 s16 y = cp.Y + y0;
2829                                                                 s16 x = cp.X + x0;
2830                                                                 v3s16 p(x,y,z);
2831                                                                 if(isInArea(p, ued) == false)
2832                                                                         continue;
2833                                                                 underground_emptiness[ued*ued*z + ued*y + x] = 1;
2834                                                         }
2835                                                 }
2836                                         }
2837                                 }
2838
2839                                 orp = rp;
2840                         }
2841                 }
2842         }
2843 #endif
2844
2845         // Set to true if has caves.
2846         // Set when some non-air is changed to air when making caves.
2847         bool has_dungeons = false;
2848
2849         /*
2850                 Apply temporary cave data to block
2851         */
2852
2853         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2854         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2855         {
2856                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2857                 {
2858                         MapNode n = block->getNode(v3s16(x0,y0,z0));
2859
2860                         // Create dungeons
2861                         if(underground_emptiness[
2862                                         ued*ued*(z0*ued/MAP_BLOCKSIZE)
2863                                         +ued*(y0*ued/MAP_BLOCKSIZE)
2864                                         +(x0*ued/MAP_BLOCKSIZE)])
2865                         {
2866                                 if(content_features(n.d).walkable/*is_ground_content(n.d)*/)
2867                                 {
2868                                         // Has now caves
2869                                         has_dungeons = true;
2870                                         // Set air to node
2871                                         n.d = CONTENT_AIR;
2872                                 }
2873                         }
2874
2875                         block->setNode(v3s16(x0,y0,z0), n);
2876                 }
2877         }
2878         
2879         /*
2880                 This is used for guessing whether or not the block should
2881                 receive sunlight from the top if the block above doesn't exist
2882         */
2883         block->setIsUnderground(completely_underground);
2884
2885         /*
2886                 Force lighting update if some part of block is partly
2887                 underground and has caves.
2888         */
2889         /*if(some_part_underground && !completely_underground && has_dungeons)
2890         {
2891                 //dstream<<"Half-ground caves"<<std::endl;
2892                 lighting_invalidated_blocks[block->getPos()] = block;
2893         }*/
2894         
2895         // DEBUG: Always update lighting
2896         //lighting_invalidated_blocks[block->getPos()] = block;
2897
2898         /*
2899                 Add some minerals
2900         */
2901
2902         if(some_part_underground)
2903         {
2904                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
2905
2906                 /*
2907                         Add meseblocks
2908                 */
2909                 for(s16 i=0; i<underground_level/4 + 1; i++)
2910                 {
2911                         if(myrand()%50 == 0)
2912                         {
2913                                 v3s16 cp(
2914                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2915                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2916                                         (myrand()%(MAP_BLOCKSIZE-2))+1
2917                                 );
2918
2919                                 MapNode n;
2920                                 n.d = CONTENT_MESE;
2921                                 
2922                                 for(u16 i=0; i<27; i++)
2923                                 {
2924                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
2925                                                 if(myrand()%8 == 0)
2926                                                         block->setNode(cp+g_27dirs[i], n);
2927                                 }
2928                         }
2929                 }
2930
2931                 /*
2932                         Add coal
2933                 */
2934                 u16 coal_amount = 30.0 * g_settings.getFloat("coal_amount");
2935                 u16 coal_rareness = 60 / coal_amount;
2936                 if(coal_rareness == 0)
2937                         coal_rareness = 1;
2938                 if(myrand()%coal_rareness == 0)
2939                 {
2940                         u16 a = myrand() % 16;
2941                         u16 amount = coal_amount * a*a*a / 1000;
2942                         for(s16 i=0; i<amount; i++)
2943                         {
2944                                 v3s16 cp(
2945                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2946                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2947                                         (myrand()%(MAP_BLOCKSIZE-2))+1
2948                                 );
2949
2950                                 MapNode n;
2951                                 n.d = CONTENT_STONE;
2952                                 n.param = MINERAL_COAL;
2953
2954                                 for(u16 i=0; i<27; i++)
2955                                 {
2956                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
2957                                                 if(myrand()%8 == 0)
2958                                                         block->setNode(cp+g_27dirs[i], n);
2959                                 }
2960                         }
2961                 }
2962
2963                 /*
2964                         Add iron
2965                 */
2966                 //TODO: change to iron_amount or whatever
2967                 u16 iron_amount = 30.0 * g_settings.getFloat("coal_amount");
2968                 u16 iron_rareness = 60 / iron_amount;
2969                 if(iron_rareness == 0)
2970                         iron_rareness = 1;
2971                 if(myrand()%iron_rareness == 0)
2972                 {
2973                         u16 a = myrand() % 16;
2974                         u16 amount = iron_amount * a*a*a / 1000;
2975                         for(s16 i=0; i<amount; i++)
2976                         {
2977                                 v3s16 cp(
2978                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2979                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2980                                         (myrand()%(MAP_BLOCKSIZE-2))+1
2981                                 );
2982
2983                                 MapNode n;
2984                                 n.d = CONTENT_STONE;
2985                                 n.param = MINERAL_IRON;
2986
2987                                 for(u16 i=0; i<27; i++)
2988                                 {
2989                                         if(block->getNode(cp+g_27dirs[i]).d == CONTENT_STONE)
2990                                                 if(myrand()%8 == 0)
2991                                                         block->setNode(cp+g_27dirs[i], n);
2992                                 }
2993                         }
2994                 }
2995         }
2996         
2997         /*
2998                 Create a few rats in empty blocks underground
2999         */
3000         if(completely_underground)
3001         {
3002                 //for(u16 i=0; i<2; i++)
3003                 {
3004                         v3s16 cp(
3005                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
3006                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
3007                                 (myrand()%(MAP_BLOCKSIZE-2))+1
3008                         );
3009
3010                         // Check that the place is empty
3011                         //if(!is_ground_content(block->getNode(cp).d))
3012                         if(1)
3013                         {
3014                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
3015                                 block->addObject(obj);
3016                         }
3017                 }
3018         }
3019         
3020         /*
3021                 Add block to sector.
3022         */
3023         sector->insertBlock(block);
3024         
3025         /*
3026                 Sector object stuff
3027         */
3028                 
3029         // An y-wise container of changed blocks
3030         core::map<s16, MapBlock*> changed_blocks_sector;
3031
3032         /*
3033                 Check if any sector's objects can be placed now.
3034                 If so, place them.
3035         */
3036         core::map<v3s16, u8> *objects = sector->getObjects();
3037         core::list<v3s16> objects_to_remove;
3038         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
3039                         i.atEnd() == false; i++)
3040         {
3041                 v3s16 p = i.getNode()->getKey();
3042                 v2s16 p2d(p.X,p.Z);
3043                 u8 d = i.getNode()->getValue();
3044
3045                 // Ground level point (user for stuff that is on ground)
3046                 v3s16 gp = p;
3047                 bool ground_found = true;
3048                 
3049                 // Search real ground level
3050                 try{
3051                         for(;;)
3052                         {
3053                                 MapNode n = sector->getNode(gp);
3054
3055                                 // If not air, go one up and continue to placing the tree
3056                                 if(n.d != CONTENT_AIR)
3057                                 {
3058                                         gp += v3s16(0,1,0);
3059                                         break;
3060                                 }
3061
3062                                 // If air, go one down
3063                                 gp += v3s16(0,-1,0);
3064                         }
3065                 }catch(InvalidPositionException &e)
3066                 {
3067                         // Ground not found.
3068                         ground_found = false;
3069                         // This is most close to ground
3070                         gp += v3s16(0,1,0);
3071                 }
3072
3073                 try
3074                 {
3075
3076                 if(d == SECTOR_OBJECT_TEST)
3077                 {
3078                         if(sector->isValidArea(p + v3s16(0,0,0),
3079                                         p + v3s16(0,0,0), &changed_blocks_sector))
3080                         {
3081                                 MapNode n;
3082                                 n.d = CONTENT_TORCH;
3083                                 sector->setNode(p, n);
3084                                 objects_to_remove.push_back(p);
3085                         }
3086                 }
3087                 else if(d == SECTOR_OBJECT_TREE_1)
3088                 {
3089                         if(ground_found == false)
3090                                 continue;
3091
3092                         v3s16 p_min = gp + v3s16(-1,0,-1);
3093                         v3s16 p_max = gp + v3s16(1,5,1);
3094                         if(sector->isValidArea(p_min, p_max,
3095                                         &changed_blocks_sector))
3096                         {
3097                                 MapNode n;
3098                                 n.d = CONTENT_TREE;
3099                                 sector->setNode(gp+v3s16(0,0,0), n);
3100                                 sector->setNode(gp+v3s16(0,1,0), n);
3101                                 sector->setNode(gp+v3s16(0,2,0), n);
3102                                 sector->setNode(gp+v3s16(0,3,0), n);
3103
3104                                 n.d = CONTENT_LEAVES;
3105
3106                                 if(myrand()%4!=0) sector->setNode(gp+v3s16(0,5,0), n);
3107
3108                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,0), n);
3109                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,0), n);
3110                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,5,-1), n);
3111                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,5,1), n);
3112                                 /*if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,1), n);
3113                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,1), n);
3114                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,-1), n);
3115                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,-1), n);*/
3116
3117                                 sector->setNode(gp+v3s16(0,4,0), n);
3118                                 
3119                                 sector->setNode(gp+v3s16(-1,4,0), n);
3120                                 sector->setNode(gp+v3s16(1,4,0), n);
3121                                 sector->setNode(gp+v3s16(0,4,-1), n);
3122                                 sector->setNode(gp+v3s16(0,4,1), n);
3123                                 sector->setNode(gp+v3s16(1,4,1), n);
3124                                 sector->setNode(gp+v3s16(-1,4,1), n);
3125                                 sector->setNode(gp+v3s16(-1,4,-1), n);
3126                                 sector->setNode(gp+v3s16(1,4,-1), n);
3127
3128                                 sector->setNode(gp+v3s16(-1,3,0), n);
3129                                 sector->setNode(gp+v3s16(1,3,0), n);
3130                                 sector->setNode(gp+v3s16(0,3,-1), n);
3131                                 sector->setNode(gp+v3s16(0,3,1), n);
3132                                 sector->setNode(gp+v3s16(1,3,1), n);
3133                                 sector->setNode(gp+v3s16(-1,3,1), n);
3134                                 sector->setNode(gp+v3s16(-1,3,-1), n);
3135                                 sector->setNode(gp+v3s16(1,3,-1), n);
3136                                 
3137                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,0), n);
3138                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,0), n);
3139                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,2,-1), n);
3140                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,2,1), n);
3141                                 /*if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,1), n);
3142                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,1), n);
3143                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,-1), n);
3144                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,-1), n);*/
3145                                 
3146                                 // Objects are identified by wanted position
3147                                 objects_to_remove.push_back(p);
3148                                 
3149                                 // Lighting has to be recalculated for this one.
3150                                 sector->getBlocksInArea(p_min, p_max, 
3151                                                 lighting_invalidated_blocks);
3152                         }
3153                 }
3154                 else if(d == SECTOR_OBJECT_BUSH_1)
3155                 {
3156                         if(ground_found == false)
3157                                 continue;
3158                         
3159                         if(sector->isValidArea(gp + v3s16(0,0,0),
3160                                         gp + v3s16(0,0,0), &changed_blocks_sector))
3161                         {
3162                                 MapNode n;
3163                                 n.d = CONTENT_LEAVES;
3164                                 sector->setNode(gp+v3s16(0,0,0), n);
3165                                 
3166                                 // Objects are identified by wanted position
3167                                 objects_to_remove.push_back(p);
3168                         }
3169                 }
3170                 else if(d == SECTOR_OBJECT_RAVINE)
3171                 {
3172                         s16 maxdepth = -20;
3173                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
3174                         v3s16 p_max = p + v3s16(6,6,6);
3175                         if(sector->isValidArea(p_min, p_max,
3176                                         &changed_blocks_sector))
3177                         {
3178                                 MapNode n;
3179                                 n.d = CONTENT_STONE;
3180                                 MapNode n2;
3181                                 n2.d = CONTENT_AIR;
3182                                 s16 depth = maxdepth + (myrand()%10);
3183                                 s16 z = 0;
3184                                 s16 minz = -6 - (-2);
3185                                 s16 maxz = 6 -1;
3186                                 for(s16 x=-6; x<=6; x++)
3187                                 {
3188                                         z += -1 + (myrand()%3);
3189                                         if(z < minz)
3190                                                 z = minz;
3191                                         if(z > maxz)
3192                                                 z = maxz;
3193                                         for(s16 y=depth+(myrand()%2); y<=6; y++)
3194                                         {
3195                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
3196                                                                 <<std::endl;*/
3197                                                 {
3198                                                         v3s16 p2 = p + v3s16(x,y,z-2);
3199                                                         //if(is_ground_content(sector->getNode(p2).d))
3200                                                         if(content_features(sector->getNode(p2).d).walkable)
3201                                                                 sector->setNode(p2, n);
3202                                                 }
3203                                                 {
3204                                                         v3s16 p2 = p + v3s16(x,y,z-1);
3205                                                         if(content_features(sector->getNode(p2).d).walkable)
3206                                                                 sector->setNode(p2, n2);
3207                                                 }
3208                                                 {
3209                                                         v3s16 p2 = p + v3s16(x,y,z+0);
3210                                                         if(content_features(sector->getNode(p2).d).walkable)
3211                                                                 sector->setNode(p2, n2);
3212                                                 }
3213                                                 {
3214                                                         v3s16 p2 = p + v3s16(x,y,z+1);
3215                                                         if(content_features(sector->getNode(p2).d).walkable)
3216                                                                 sector->setNode(p2, n);
3217                                                 }
3218
3219                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
3220                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
3221                                         }
3222                                 }
3223                                 
3224                                 objects_to_remove.push_back(p);
3225                                 
3226                                 // Lighting has to be recalculated for this one.
3227                                 sector->getBlocksInArea(p_min, p_max, 
3228                                                 lighting_invalidated_blocks);
3229                         }
3230                 }
3231                 else
3232                 {
3233                         dstream<<"ServerMap::generateBlock(): "
3234                                         "Invalid heightmap object"
3235                                         <<std::endl;
3236                 }
3237
3238                 }//try
3239                 catch(InvalidPositionException &e)
3240                 {
3241                         dstream<<"WARNING: "<<__FUNCTION_NAME
3242                                         <<": while inserting object "<<(int)d
3243                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
3244                                         <<" InvalidPositionException.what()="
3245                                         <<e.what()<<std::endl;
3246                         // This is not too fatal and seems to happen sometimes.
3247                         assert(0);
3248                 }
3249         }
3250
3251         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
3252                         i != objects_to_remove.end(); i++)
3253         {
3254                 objects->remove(*i);
3255         }
3256         
3257         /*
3258                 Translate sector's changed blocks to global changed blocks
3259         */
3260         
3261         for(core::map<s16, MapBlock*>::Iterator
3262                         i = changed_blocks_sector.getIterator();
3263                         i.atEnd() == false; i++)
3264         {
3265                 MapBlock *block = i.getNode()->getValue();
3266
3267                 changed_blocks.insert(block->getPos(), block);
3268         }
3269
3270         block->setLightingExpired(true);
3271         
3272 #if 0
3273         /*
3274                 Debug information
3275         */
3276         dstream
3277         <<"lighting_invalidated_blocks.size()"
3278         <<", has_dungeons"
3279         <<", completely_ug"
3280         <<", some_part_ug"
3281         <<"  "<<lighting_invalidated_blocks.size()
3282         <<", "<<has_dungeons
3283         <<", "<<completely_underground
3284         <<", "<<some_part_underground
3285         <<std::endl;
3286 #endif
3287
3288         return block;
3289 }
3290
3291 MapBlock * ServerMap::emergeBlock(
3292                 v3s16 p,
3293                 bool only_from_disk,
3294                 core::map<v3s16, MapBlock*> &changed_blocks,
3295                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
3296 )
3297 {
3298         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
3299                         __FUNCTION_NAME,
3300                         p.X, p.Y, p.Z, only_from_disk);
3301         
3302         /*dstream<<"emergeBlock(): "
3303                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3304                         <<std::endl;*/
3305                         
3306         v2s16 p2d(p.X, p.Z);
3307         s16 block_y = p.Y;
3308         /*
3309                 This will create or load a sector if not found in memory.
3310                 If block exists on disk, it will be loaded.
3311
3312                 NOTE: On old save formats, this will be slow, as it generates
3313                       lighting on blocks for them.
3314         */
3315         ServerMapSector *sector;
3316         try{
3317                 sector = (ServerMapSector*)emergeSector(p2d);
3318                 assert(sector->getId() == MAPSECTOR_SERVER);
3319         }
3320         /*catch(InvalidPositionException &e)
3321         {
3322                 dstream<<"emergeBlock: emergeSector() failed"<<std::endl;
3323                 throw e;
3324         }*/
3325         catch(std::exception &e)
3326         {
3327                 dstream<<"emergeBlock: emergeSector() failed: "
3328                                 <<e.what()<<std::endl;
3329                 throw e;
3330         }
3331
3332         /*
3333                 Try to get a block from the sector
3334         */
3335
3336         bool does_not_exist = false;
3337         bool lighting_expired = false;
3338         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
3339
3340         if(block == NULL)
3341         {
3342                 does_not_exist = true;
3343         }
3344         else if(block->isDummy() == true)
3345         {
3346                 does_not_exist = true;
3347         }
3348         else if(block->getLightingExpired())
3349         {
3350                 lighting_expired = true;
3351         }
3352         else
3353         {
3354                 // Valid block
3355                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
3356                 return block;
3357         }
3358         
3359         /*
3360                 If block was not found on disk and not going to generate a
3361                 new one, make sure there is a dummy block in place.
3362         */
3363         if(only_from_disk && (does_not_exist || lighting_expired))
3364         {
3365                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
3366
3367                 if(block == NULL)
3368                 {
3369                         // Create dummy block
3370                         block = new MapBlock(this, p, true);
3371
3372                         // Add block to sector
3373                         sector->insertBlock(block);
3374                 }
3375                 // Done.
3376                 return block;
3377         }
3378
3379         //dstream<<"Not found on disk, generating."<<std::endl;
3380         // 0ms
3381         //TimeTaker("emergeBlock() generate");
3382
3383         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
3384
3385         /*
3386                 If the block doesn't exist, generate the block.
3387         */
3388         if(does_not_exist)
3389         {
3390                 block = generateBlock(p, block, sector, changed_blocks,
3391                                 lighting_invalidated_blocks); 
3392         }
3393
3394         if(lighting_expired)
3395         {
3396                 lighting_invalidated_blocks.insert(p, block);
3397         }
3398
3399         /*
3400                 Initially update sunlight
3401         */
3402         
3403         {
3404                 core::map<v3s16, bool> light_sources;
3405                 bool black_air_left = false;
3406                 bool bottom_invalid =
3407                                 block->propagateSunlight(light_sources, true,
3408                                 &black_air_left, true);
3409
3410                 // If sunlight didn't reach everywhere and part of block is
3411                 // above ground, lighting has to be properly updated
3412                 //if(black_air_left && some_part_underground)
3413                 if(black_air_left)
3414                 {
3415                         lighting_invalidated_blocks[block->getPos()] = block;
3416                 }
3417
3418                 if(bottom_invalid)
3419                 {
3420                         lighting_invalidated_blocks[block->getPos()] = block;
3421                 }
3422         }
3423         
3424         /*
3425                 Debug mode operation
3426         */
3427         bool haxmode = g_settings.getBool("haxmode");
3428         if(haxmode)
3429         {
3430                 // Don't calculate lighting at all
3431                 //lighting_invalidated_blocks.clear();
3432         }
3433
3434         return block;
3435 }
3436
3437 void ServerMap::createDir(std::string path)
3438 {
3439         if(fs::CreateDir(path) == false)
3440         {
3441                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
3442                                 <<"\""<<path<<"\""<<std::endl;
3443                 throw BaseException("ServerMap failed to create directory");
3444         }
3445 }
3446
3447 std::string ServerMap::getSectorSubDir(v2s16 pos)
3448 {
3449         char cc[9];
3450         snprintf(cc, 9, "%.4x%.4x",
3451                         (unsigned int)pos.X&0xffff,
3452                         (unsigned int)pos.Y&0xffff);
3453
3454         return std::string(cc);
3455 }
3456
3457 std::string ServerMap::getSectorDir(v2s16 pos)
3458 {
3459         return m_savedir + "/sectors/" + getSectorSubDir(pos);
3460 }
3461
3462 v2s16 ServerMap::getSectorPos(std::string dirname)
3463 {
3464         if(dirname.size() != 8)
3465                 throw InvalidFilenameException("Invalid sector directory name");
3466         unsigned int x, y;
3467         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
3468         if(r != 2)
3469                 throw InvalidFilenameException("Invalid sector directory name");
3470         v2s16 pos((s16)x, (s16)y);
3471         return pos;
3472 }
3473
3474 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
3475 {
3476         v2s16 p2d = getSectorPos(sectordir);
3477
3478         if(blockfile.size() != 4){
3479                 throw InvalidFilenameException("Invalid block filename");
3480         }
3481         unsigned int y;
3482         int r = sscanf(blockfile.c_str(), "%4x", &y);
3483         if(r != 1)
3484                 throw InvalidFilenameException("Invalid block filename");
3485         return v3s16(p2d.X, y, p2d.Y);
3486 }
3487
3488 // Debug helpers
3489 #define ENABLE_SECTOR_SAVING 1
3490 #define ENABLE_SECTOR_LOADING 1
3491 #define ENABLE_BLOCK_SAVING 1
3492 #define ENABLE_BLOCK_LOADING 1
3493
3494 void ServerMap::save(bool only_changed)
3495 {
3496         DSTACK(__FUNCTION_NAME);
3497         if(m_map_saving_enabled == false)
3498         {
3499                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
3500                 return;
3501         }
3502         
3503         if(only_changed == false)
3504                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
3505                                 <<std::endl;
3506         
3507         saveMasterHeightmap();
3508         
3509         u32 sector_meta_count = 0;
3510         u32 block_count = 0;
3511         
3512         { //sectorlock
3513         JMutexAutoLock lock(m_sector_mutex);
3514         
3515         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
3516         for(; i.atEnd() == false; i++)
3517         {
3518                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
3519                 assert(sector->getId() == MAPSECTOR_SERVER);
3520                 
3521                 if(ENABLE_SECTOR_SAVING)
3522                 {
3523                         if(sector->differs_from_disk || only_changed == false)
3524                         {
3525                                 saveSectorMeta(sector);
3526                                 sector_meta_count++;
3527                         }
3528                 }
3529                 if(ENABLE_BLOCK_SAVING)
3530                 {
3531                         core::list<MapBlock*> blocks;
3532                         sector->getBlocks(blocks);
3533                         core::list<MapBlock*>::Iterator j;
3534                         for(j=blocks.begin(); j!=blocks.end(); j++)
3535                         {
3536                                 MapBlock *block = *j;
3537                                 if(block->getChangedFlag() || only_changed == false)
3538                                 {
3539                                         saveBlock(block);
3540                                         block_count++;
3541                                 }
3542                         }
3543                 }
3544         }
3545
3546         }//sectorlock
3547         
3548         /*
3549                 Only print if something happened or saved whole map
3550         */
3551         if(only_changed == false || sector_meta_count != 0
3552                         || block_count != 0)
3553         {
3554                 dstream<<DTIME<<"ServerMap: Written: "
3555                                 <<sector_meta_count<<" sector metadata files, "
3556                                 <<block_count<<" block files"
3557                                 <<std::endl;
3558         }
3559 }
3560
3561 void ServerMap::loadAll()
3562 {
3563         DSTACK(__FUNCTION_NAME);
3564         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
3565
3566         loadMasterHeightmap();
3567
3568         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
3569
3570         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
3571         
3572         JMutexAutoLock lock(m_sector_mutex);
3573         
3574         s32 counter = 0;
3575         s32 printed_counter = -100000;
3576         s32 count = list.size();
3577
3578         std::vector<fs::DirListNode>::iterator i;
3579         for(i=list.begin(); i!=list.end(); i++)
3580         {
3581                 if(counter > printed_counter + 10)
3582                 {
3583                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
3584                         printed_counter = counter;
3585                 }
3586                 counter++;
3587
3588                 MapSector *sector = NULL;
3589
3590                 // We want directories
3591                 if(i->dir == false)
3592                         continue;
3593                 try{
3594                         sector = loadSectorMeta(i->name);
3595                 }
3596                 catch(InvalidFilenameException &e)
3597                 {
3598                         // This catches unknown crap in directory
3599                 }
3600                 
3601                 if(ENABLE_BLOCK_LOADING)
3602                 {
3603                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3604                                         (m_savedir+"/sectors/"+i->name);
3605                         std::vector<fs::DirListNode>::iterator i2;
3606                         for(i2=list2.begin(); i2!=list2.end(); i2++)
3607                         {
3608                                 // We want files
3609                                 if(i2->dir)
3610                                         continue;
3611                                 try{
3612                                         loadBlock(i->name, i2->name, sector);
3613                                 }
3614                                 catch(InvalidFilenameException &e)
3615                                 {
3616                                         // This catches unknown crap in directory
3617                                 }
3618                         }
3619                 }
3620         }
3621         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
3622 }
3623
3624 void ServerMap::saveMasterHeightmap()
3625 {
3626         DSTACK(__FUNCTION_NAME);
3627         createDir(m_savedir);
3628         
3629         std::string fullpath = m_savedir + "/master_heightmap";
3630         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3631         if(o.good() == false)
3632                 throw FileNotGoodException("Cannot open master heightmap");
3633         
3634         // Format used for writing
3635         u8 version = SER_FMT_VER_HIGHEST;
3636
3637 #if 0
3638         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
3639         /*
3640                 [0] u8 serialization version
3641                 [1] X master heightmap
3642         */
3643         u32 fullsize = 1 + hmdata.getSize();
3644         SharedBuffer<u8> data(fullsize);
3645
3646         data[0] = version;
3647         memcpy(&data[1], *hmdata, hmdata.getSize());
3648
3649         o.write((const char*)*data, fullsize);
3650 #endif
3651         
3652         m_heightmap->serialize(o, version);
3653 }
3654
3655 void ServerMap::loadMasterHeightmap()
3656 {
3657         DSTACK(__FUNCTION_NAME);
3658         std::string fullpath = m_savedir + "/master_heightmap";
3659         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3660         if(is.good() == false)
3661                 throw FileNotGoodException("Cannot open master heightmap");
3662         
3663         if(m_heightmap != NULL)
3664                 delete m_heightmap;
3665                 
3666         m_heightmap = UnlimitedHeightmap::deSerialize(is, &m_padb);
3667 }
3668
3669 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3670 {
3671         DSTACK(__FUNCTION_NAME);
3672         // Format used for writing
3673         u8 version = SER_FMT_VER_HIGHEST;
3674         // Get destination
3675         v2s16 pos = sector->getPos();
3676         createDir(m_savedir);
3677         createDir(m_savedir+"/sectors");
3678         std::string dir = getSectorDir(pos);
3679         createDir(dir);
3680         
3681         std::string fullpath = dir + "/heightmap";
3682         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3683         if(o.good() == false)
3684                 throw FileNotGoodException("Cannot open master heightmap");
3685
3686         sector->serialize(o, version);
3687         
3688         sector->differs_from_disk = false;
3689 }
3690
3691 MapSector* ServerMap::loadSectorMeta(std::string dirname)
3692 {
3693         DSTACK(__FUNCTION_NAME);
3694         // Get destination
3695         v2s16 p2d = getSectorPos(dirname);
3696         std::string dir = m_savedir + "/sectors/" + dirname;
3697         
3698         std::string fullpath = dir + "/heightmap";
3699         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3700         if(is.good() == false)
3701                 throw FileNotGoodException("Cannot open sector heightmap");
3702
3703         ServerMapSector *sector = ServerMapSector::deSerialize
3704                         (is, this, p2d, &m_hwrapper, m_sectors);
3705         
3706         sector->differs_from_disk = false;
3707
3708         return sector;
3709 }
3710
3711 bool ServerMap::loadSectorFull(v2s16 p2d)
3712 {
3713         DSTACK(__FUNCTION_NAME);
3714         std::string sectorsubdir = getSectorSubDir(p2d);
3715
3716         MapSector *sector = NULL;
3717
3718         JMutexAutoLock lock(m_sector_mutex);
3719
3720         try{
3721                 sector = loadSectorMeta(sectorsubdir);
3722         }
3723         catch(InvalidFilenameException &e)
3724         {
3725                 return false;
3726         }
3727         catch(FileNotGoodException &e)
3728         {
3729                 return false;
3730         }
3731         catch(std::exception &e)
3732         {
3733                 return false;
3734         }
3735
3736         if(ENABLE_BLOCK_LOADING)
3737         {
3738                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
3739                                 (m_savedir+"/sectors/"+sectorsubdir);
3740                 std::vector<fs::DirListNode>::iterator i2;
3741                 for(i2=list2.begin(); i2!=list2.end(); i2++)
3742                 {
3743                         // We want files
3744                         if(i2->dir)
3745                                 continue;
3746                         try{
3747                                 loadBlock(sectorsubdir, i2->name, sector);
3748                         }
3749                         catch(InvalidFilenameException &e)
3750                         {
3751                                 // This catches unknown crap in directory
3752                         }
3753                 }
3754         }
3755         return true;
3756 }
3757
3758 #if 0
3759 bool ServerMap::deFlushSector(v2s16 p2d)
3760 {
3761         DSTACK(__FUNCTION_NAME);
3762         // See if it already exists in memory
3763         try{
3764                 MapSector *sector = getSectorNoGenerate(p2d);
3765                 return true;
3766         }
3767         catch(InvalidPositionException &e)
3768         {
3769                 /*
3770                         Try to load the sector from disk.
3771                 */
3772                 if(loadSectorFull(p2d) == true)
3773                 {
3774                         return true;
3775                 }
3776         }
3777         return false;
3778 }
3779 #endif
3780
3781 void ServerMap::saveBlock(MapBlock *block)
3782 {
3783         DSTACK(__FUNCTION_NAME);
3784         /*
3785                 Dummy blocks are not written
3786         */
3787         if(block->isDummy())
3788         {
3789                 /*v3s16 p = block->getPos();
3790                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3791                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3792                 return;
3793         }
3794
3795         // Format used for writing
3796         u8 version = SER_FMT_VER_HIGHEST;
3797         // Get destination
3798         v3s16 p3d = block->getPos();
3799         v2s16 p2d(p3d.X, p3d.Z);
3800         createDir(m_savedir);
3801         createDir(m_savedir+"/sectors");
3802         std::string dir = getSectorDir(p2d);
3803         createDir(dir);
3804         
3805         // Block file is map/sectors/xxxxxxxx/xxxx
3806         char cc[5];
3807         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
3808         std::string fullpath = dir + "/" + cc;
3809         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3810         if(o.good() == false)
3811                 throw FileNotGoodException("Cannot open block data");
3812
3813         /*
3814                 [0] u8 serialization version
3815                 [1] data
3816         */
3817         o.write((char*)&version, 1);
3818         
3819         block->serialize(o, version);
3820
3821         /*
3822                 Versions up from 9 have block objects.
3823         */
3824         if(version >= 9)
3825         {
3826                 block->serializeObjects(o, version);
3827         }
3828         
3829         // We just wrote it to the disk
3830         block->resetChangedFlag();
3831 }
3832
3833 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
3834 {
3835         DSTACK(__FUNCTION_NAME);
3836
3837         try{
3838
3839         // Block file is map/sectors/xxxxxxxx/xxxx
3840         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
3841         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3842         if(is.good() == false)
3843                 throw FileNotGoodException("Cannot open block file");
3844
3845         v3s16 p3d = getBlockPos(sectordir, blockfile);
3846         v2s16 p2d(p3d.X, p3d.Z);
3847         
3848         assert(sector->getPos() == p2d);
3849         
3850         u8 version = SER_FMT_VER_INVALID;
3851         is.read((char*)&version, 1);
3852
3853         /*u32 block_size = MapBlock::serializedLength(version);
3854         SharedBuffer<u8> data(block_size);
3855         is.read((char*)*data, block_size);*/
3856
3857         // This will always return a sector because we're the server
3858         //MapSector *sector = emergeSector(p2d);
3859
3860         MapBlock *block = NULL;
3861         bool created_new = false;
3862         try{
3863                 block = sector->getBlockNoCreate(p3d.Y);
3864         }
3865         catch(InvalidPositionException &e)
3866         {
3867                 block = sector->createBlankBlockNoInsert(p3d.Y);
3868                 created_new = true;
3869         }
3870         
3871         // deserialize block data
3872         block->deSerialize(is, version);
3873         
3874         /*
3875                 Versions up from 9 have block objects.
3876         */
3877         if(version >= 9)
3878         {
3879                 block->updateObjects(is, version, NULL, 0);
3880         }
3881
3882         if(created_new)
3883                 sector->insertBlock(block);
3884         
3885         /*
3886                 Convert old formats to new and save
3887         */
3888
3889         // Save old format blocks in new format
3890         if(version < SER_FMT_VER_HIGHEST)
3891         {
3892                 saveBlock(block);
3893         }
3894         
3895         // We just loaded it from the disk, so it's up-to-date.
3896         block->resetChangedFlag();
3897
3898         }
3899         catch(SerializationError &e)
3900         {
3901                 dstream<<"WARNING: Invalid block data on disk "
3902                                 "(SerializationError). Ignoring."
3903                                 <<std::endl;
3904         }
3905 }
3906
3907 // Gets from master heightmap
3908 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
3909 {
3910         assert(m_heightmap != NULL);
3911         /*
3912                 Corner definition:
3913                 v2s16(0,0),
3914                 v2s16(1,0),
3915                 v2s16(1,1),
3916                 v2s16(0,1),
3917         */
3918         corners[0] = m_heightmap->getGroundHeight
3919                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
3920         corners[1] = m_heightmap->getGroundHeight
3921                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
3922         corners[2] = m_heightmap->getGroundHeight
3923                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
3924         corners[3] = m_heightmap->getGroundHeight
3925                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
3926 }
3927
3928 void ServerMap::PrintInfo(std::ostream &out)
3929 {
3930         out<<"ServerMap: ";
3931 }
3932
3933 #ifndef SERVER
3934
3935 /*
3936         ClientMap
3937 */
3938
3939 ClientMap::ClientMap(
3940                 Client *client,
3941                 MapDrawControl &control,
3942                 scene::ISceneNode* parent,
3943                 scene::ISceneManager* mgr,
3944                 s32 id
3945 ):
3946         Map(dout_client),
3947         scene::ISceneNode(parent, mgr, id),
3948         m_client(client),
3949         mesh(NULL),
3950         m_control(control)
3951 {
3952         mesh_mutex.Init();
3953
3954         /*m_box = core::aabbox3d<f32>(0,0,0,
3955                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
3956         /*m_box = core::aabbox3d<f32>(0,0,0,
3957                         map->getSizeNodes().X * BS,
3958                         map->getSizeNodes().Y * BS,
3959                         map->getSizeNodes().Z * BS);*/
3960         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3961                         BS*1000000,BS*1000000,BS*1000000);
3962         
3963         //setPosition(v3f(BS,BS,BS));
3964 }
3965
3966 ClientMap::~ClientMap()
3967 {
3968         JMutexAutoLock lock(mesh_mutex);
3969         
3970         if(mesh != NULL)
3971         {
3972                 mesh->drop();
3973                 mesh = NULL;
3974         }
3975 }
3976
3977 MapSector * ClientMap::emergeSector(v2s16 p2d)
3978 {
3979         DSTACK(__FUNCTION_NAME);
3980         // Check that it doesn't exist already
3981         try{
3982                 return getSectorNoGenerate(p2d);
3983         }
3984         catch(InvalidPositionException &e)
3985         {
3986         }
3987         
3988         // Create a sector with no heightmaps
3989         ClientMapSector *sector = new ClientMapSector(this, p2d);
3990         
3991         {
3992                 JMutexAutoLock lock(m_sector_mutex);
3993                 m_sectors.insert(p2d, sector);
3994         }
3995         
3996         return sector;
3997 }
3998
3999 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
4000 {
4001         DSTACK(__FUNCTION_NAME);
4002         ClientMapSector *sector = NULL;
4003
4004         JMutexAutoLock lock(m_sector_mutex);
4005         
4006         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
4007
4008         if(n != NULL)
4009         {
4010                 sector = (ClientMapSector*)n->getValue();
4011                 assert(sector->getId() == MAPSECTOR_CLIENT);
4012         }
4013         else
4014         {
4015                 sector = new ClientMapSector(this, p2d);
4016                 {
4017                         JMutexAutoLock lock(m_sector_mutex);
4018                         m_sectors.insert(p2d, sector);
4019                 }
4020         }
4021
4022         sector->deSerialize(is);
4023 }
4024
4025 void ClientMap::OnRegisterSceneNode()
4026 {
4027         if(IsVisible)
4028         {
4029                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
4030                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
4031         }
4032
4033         ISceneNode::OnRegisterSceneNode();
4034 }
4035
4036 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
4037 {
4038         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
4039         DSTACK(__FUNCTION_NAME);
4040
4041         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
4042
4043         /*
4044                 Get time for measuring timeout.
4045                 
4046                 Measuring time is very useful for long delays when the
4047                 machine is swapping a lot.
4048         */
4049         int time1 = time(0);
4050
4051         u32 daynight_ratio = m_client->getDayNightRatio();
4052
4053         m_camera_mutex.Lock();
4054         v3f camera_position = m_camera_position;
4055         v3f camera_direction = m_camera_direction;
4056         m_camera_mutex.Unlock();
4057
4058         /*
4059                 Get all blocks and draw all visible ones
4060         */
4061
4062         v3s16 cam_pos_nodes(
4063                         camera_position.X / BS,
4064                         camera_position.Y / BS,
4065                         camera_position.Z / BS);
4066
4067         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
4068
4069         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
4070         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
4071
4072         // Take a fair amount as we will be dropping more out later
4073         v3s16 p_blocks_min(
4074                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
4075                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
4076                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
4077         v3s16 p_blocks_max(
4078                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
4079                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
4080                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
4081         
4082         u32 vertex_count = 0;
4083         
4084         // For limiting number of mesh updates per frame
4085         u32 mesh_update_count = 0;
4086         
4087         u32 blocks_would_have_drawn = 0;
4088         u32 blocks_drawn = 0;
4089
4090         //NOTE: The sectors map should be locked but we're not doing it
4091         // because it'd cause too much delays
4092
4093         int timecheck_counter = 0;
4094         core::map<v2s16, MapSector*>::Iterator si;
4095         si = m_sectors.getIterator();
4096         for(; si.atEnd() == false; si++)
4097         {
4098                 {
4099                         timecheck_counter++;
4100                         if(timecheck_counter > 50)
4101                         {
4102                                 int time2 = time(0);
4103                                 if(time2 > time1 + 4)
4104                                 {
4105                                         dstream<<"ClientMap::renderMap(): "
4106                                                 "Rendering takes ages, returning."
4107                                                 <<std::endl;
4108                                         return;
4109                                 }
4110                         }
4111                 }
4112
4113                 MapSector *sector = si.getNode()->getValue();
4114                 v2s16 sp = sector->getPos();
4115                 
4116                 if(m_control.range_all == false)
4117                 {
4118                         if(sp.X < p_blocks_min.X
4119                         || sp.X > p_blocks_max.X
4120                         || sp.Y < p_blocks_min.Z
4121                         || sp.Y > p_blocks_max.Z)
4122                                 continue;
4123                 }
4124
4125                 core::list< MapBlock * > sectorblocks;
4126                 sector->getBlocks(sectorblocks);
4127                 
4128                 /*
4129                         Draw blocks
4130                 */
4131
4132                 core::list< MapBlock * >::Iterator i;
4133                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
4134                 {
4135                         MapBlock *block = *i;
4136
4137                         /*
4138                                 Compare block position to camera position, skip
4139                                 if not seen on display
4140                         */
4141                         
4142                         float range = 100000 * BS;
4143                         if(m_control.range_all == false)
4144                                 range = m_control.wanted_range * BS;
4145
4146                         if(isBlockInSight(block->getPos(), camera_position,
4147                                         camera_direction, range) == false)
4148                         {
4149                                 continue;
4150                         }
4151
4152 #if 0                   
4153                         v3s16 blockpos_nodes = block->getPosRelative();
4154                         
4155                         // Block center position
4156                         v3f blockpos(
4157                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
4158                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
4159                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
4160                         );
4161
4162                         // Block position relative to camera
4163                         v3f blockpos_relative = blockpos - camera_position;
4164
4165                         // Distance in camera direction (+=front, -=back)
4166                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
4167
4168                         // Total distance
4169                         f32 d = blockpos_relative.getLength();
4170                         
4171                         if(m_control.range_all == false)
4172                         {
4173                                 // If block is far away, don't draw it
4174                                 if(d > m_control.wanted_range * BS)
4175                                         continue;
4176                         }
4177                         
4178                         // Maximum radius of a block
4179                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
4180                         
4181                         // If block is (nearly) touching the camera, don't
4182                         // bother validating further (that is, render it anyway)
4183                         if(d > block_max_radius * 1.5)
4184                         {
4185                                 // Cosine of the angle between the camera direction
4186                                 // and the block direction (camera_direction is an unit vector)
4187                                 f32 cosangle = dforward / d;
4188                                 
4189                                 // Compensate for the size of the block
4190                                 // (as the block has to be shown even if it's a bit off FOV)
4191                                 // This is an estimate.
4192                                 cosangle += block_max_radius / dforward;
4193
4194                                 // If block is not in the field of view, skip it
4195                                 //if(cosangle < cos(FOV_ANGLE/2))
4196                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
4197                                         continue;
4198                         }
4199 #endif                  
4200
4201                         v3s16 blockpos_nodes = block->getPosRelative();
4202                         
4203                         // Block center position
4204                         v3f blockpos(
4205                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
4206                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
4207                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
4208                         );
4209
4210                         // Block position relative to camera
4211                         v3f blockpos_relative = blockpos - camera_position;
4212
4213                         // Total distance
4214                         f32 d = blockpos_relative.getLength();
4215                         
4216 #if 1
4217                         /*
4218                                 Update expired mesh
4219                         */
4220
4221                         bool mesh_expired = false;
4222                         
4223                         {
4224                                 JMutexAutoLock lock(block->mesh_mutex);
4225
4226                                 mesh_expired = block->getMeshExpired();
4227
4228                                 // Mesh has not been expired and there is no mesh:
4229                                 // block has no content
4230                                 if(block->mesh == NULL && mesh_expired == false)
4231                                         continue;
4232                         }
4233
4234                         f32 faraway = BS*50;
4235                         //f32 faraway = m_control.wanted_range * BS;
4236                         
4237                         /*
4238                                 This has to be done with the mesh_mutex unlocked
4239                         */
4240                         // Pretty random but this should work somewhat nicely
4241                         if(mesh_expired && (
4242                                         (mesh_update_count < 3
4243                                                 && (d < faraway || mesh_update_count < 2)
4244                                         )
4245                                         || 
4246                                         (m_control.range_all && mesh_update_count < 20)
4247                                 )
4248                         )
4249                         /*if(mesh_expired && mesh_update_count < 6
4250                                         && (d < faraway || mesh_update_count < 3))*/
4251                         {
4252                                 mesh_update_count++;
4253
4254                                 // Mesh has been expired: generate new mesh
4255                                 //block->updateMeshes(daynight_i);
4256                                 block->updateMesh(daynight_ratio);
4257
4258                                 mesh_expired = false;
4259                         }
4260                         
4261                         /*
4262                                 Don't draw an expired mesh that is far away
4263                         */
4264                         /*if(mesh_expired && d >= faraway)
4265                         //if(mesh_expired)
4266                         {
4267                                 // Instead, delete it
4268                                 JMutexAutoLock lock(block->mesh_mutex);
4269                                 if(block->mesh)
4270                                 {
4271                                         block->mesh->drop();
4272                                         block->mesh = NULL;
4273                                 }
4274                                 // And continue to next block
4275                                 continue;
4276                         }*/
4277 #endif
4278                         /*
4279                                 Draw the faces of the block
4280                         */
4281                         {
4282                                 JMutexAutoLock lock(block->mesh_mutex);
4283
4284                                 scene::SMesh *mesh = block->mesh;
4285
4286                                 if(mesh == NULL)
4287                                         continue;
4288                                 
4289                                 blocks_would_have_drawn++;
4290                                 if(blocks_drawn >= m_control.wanted_max_blocks
4291                                                 && m_control.range_all == false
4292                                                 && d > m_control.wanted_min_range * BS)
4293                                         continue;
4294                                 blocks_drawn++;
4295
4296                                 u32 c = mesh->getMeshBufferCount();
4297
4298                                 for(u32 i=0; i<c; i++)
4299                                 {
4300                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
4301                                         const video::SMaterial& material = buf->getMaterial();
4302                                         video::IMaterialRenderer* rnd =
4303                                                         driver->getMaterialRenderer(material.MaterialType);
4304                                         bool transparent = (rnd && rnd->isTransparent());
4305                                         // Render transparent on transparent pass and likewise.
4306                                         if(transparent == is_transparent_pass)
4307                                         {
4308                                                 driver->setMaterial(buf->getMaterial());
4309                                                 driver->drawMeshBuffer(buf);
4310                                                 vertex_count += buf->getVertexCount();
4311                                         }
4312                                 }
4313                         }
4314                 } // foreach sectorblocks
4315         }
4316         
4317         m_control.blocks_drawn = blocks_drawn;
4318         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
4319
4320         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
4321                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
4322 }
4323
4324 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
4325                 core::map<v3s16, MapBlock*> *affected_blocks)
4326 {
4327         bool changed = false;
4328         /*
4329                 Add it to all blocks touching it
4330         */
4331         v3s16 dirs[7] = {
4332                 v3s16(0,0,0), // this
4333                 v3s16(0,0,1), // back
4334                 v3s16(0,1,0), // top
4335                 v3s16(1,0,0), // right
4336                 v3s16(0,0,-1), // front
4337                 v3s16(0,-1,0), // bottom
4338                 v3s16(-1,0,0), // left
4339         };
4340         for(u16 i=0; i<7; i++)
4341         {
4342                 v3s16 p2 = p + dirs[i];
4343                 // Block position of neighbor (or requested) node
4344                 v3s16 blockpos = getNodeBlockPos(p2);
4345                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4346                 if(blockref == NULL)
4347                         continue;
4348                 // Relative position of requested node
4349                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4350                 if(blockref->setTempMod(relpos, mod))
4351                 {
4352                         changed = true;
4353                 }
4354         }
4355         if(changed && affected_blocks!=NULL)
4356         {
4357                 for(u16 i=0; i<7; i++)
4358                 {
4359                         v3s16 p2 = p + dirs[i];
4360                         // Block position of neighbor (or requested) node
4361                         v3s16 blockpos = getNodeBlockPos(p2);
4362                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4363                         if(blockref == NULL)
4364                                 continue;
4365                         affected_blocks->insert(blockpos, blockref);
4366                 }
4367         }
4368         return changed;
4369 }
4370
4371 bool ClientMap::clearTempMod(v3s16 p,
4372                 core::map<v3s16, MapBlock*> *affected_blocks)
4373 {
4374         bool changed = false;
4375         v3s16 dirs[7] = {
4376                 v3s16(0,0,0), // this
4377                 v3s16(0,0,1), // back
4378                 v3s16(0,1,0), // top
4379                 v3s16(1,0,0), // right
4380                 v3s16(0,0,-1), // front
4381                 v3s16(0,-1,0), // bottom
4382                 v3s16(-1,0,0), // left
4383         };
4384         for(u16 i=0; i<7; i++)
4385         {
4386                 v3s16 p2 = p + dirs[i];
4387                 // Block position of neighbor (or requested) node
4388                 v3s16 blockpos = getNodeBlockPos(p2);
4389                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4390                 if(blockref == NULL)
4391                         continue;
4392                 // Relative position of requested node
4393                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4394                 if(blockref->clearTempMod(relpos))
4395                 {
4396                         changed = true;
4397                 }
4398         }
4399         if(changed && affected_blocks!=NULL)
4400         {
4401                 for(u16 i=0; i<7; i++)
4402                 {
4403                         v3s16 p2 = p + dirs[i];
4404                         // Block position of neighbor (or requested) node
4405                         v3s16 blockpos = getNodeBlockPos(p2);
4406                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4407                         if(blockref == NULL)
4408                                 continue;
4409                         affected_blocks->insert(blockpos, blockref);
4410                 }
4411         }
4412         return changed;
4413 }
4414
4415 void ClientMap::PrintInfo(std::ostream &out)
4416 {
4417         out<<"ClientMap: ";
4418 }
4419
4420 #endif // !SERVER
4421
4422 /*
4423         MapVoxelManipulator
4424 */
4425
4426 MapVoxelManipulator::MapVoxelManipulator(Map *map)
4427 {
4428         m_map = map;
4429 }
4430
4431 MapVoxelManipulator::~MapVoxelManipulator()
4432 {
4433         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4434                         <<std::endl;*/
4435 }
4436
4437 #if 1
4438 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4439 {
4440         TimeTaker timer1("emerge", &emerge_time);
4441
4442         // Units of these are MapBlocks
4443         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4444         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4445
4446         VoxelArea block_area_nodes
4447                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4448
4449         addArea(block_area_nodes);
4450
4451         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4452         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4453         for(s32 x=p_min.X; x<=p_max.X; x++)
4454         {
4455                 v3s16 p(x,y,z);
4456                 core::map<v3s16, bool>::Node *n;
4457                 n = m_loaded_blocks.find(p);
4458                 if(n != NULL)
4459                         continue;
4460                 
4461                 bool block_data_inexistent = false;
4462                 try
4463                 {
4464                         TimeTaker timer1("emerge load", &emerge_load_time);
4465
4466                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
4467                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4468                                         <<" wanted area: ";
4469                         a.print(dstream);
4470                         dstream<<std::endl;*/
4471                         
4472                         MapBlock *block = m_map->getBlockNoCreate(p);
4473                         if(block->isDummy())
4474                                 block_data_inexistent = true;
4475                         else
4476                                 block->copyTo(*this);
4477                 }
4478                 catch(InvalidPositionException &e)
4479                 {
4480                         block_data_inexistent = true;
4481                 }
4482
4483                 if(block_data_inexistent)
4484                 {
4485                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4486                         // Fill with VOXELFLAG_INEXISTENT
4487                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4488                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4489                         {
4490                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4491                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4492                         }
4493                 }
4494
4495                 m_loaded_blocks.insert(p, true);
4496         }
4497
4498         //dstream<<"emerge done"<<std::endl;
4499 }
4500 #endif
4501
4502 #if 0
4503 /*
4504         NOTE: This is slow
4505 */
4506 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4507 {
4508         TimeTaker timer1("emerge", &emerge_time);
4509         
4510         v3s16 size = a.getExtent();
4511         
4512         VoxelArea padded = a;
4513         padded.pad(m_area.getExtent() / 4);
4514         addArea(padded);
4515
4516         for(s16 z=0; z<size.Z; z++)
4517         for(s16 y=0; y<size.Y; y++)
4518         for(s16 x=0; x<size.X; x++)
4519         {
4520                 v3s16 p(x,y,z);
4521                 s32 i = m_area.index(a.MinEdge + p);
4522                 // Don't touch nodes that have already been loaded
4523                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
4524                         continue;
4525                 try
4526                 {
4527                         TimeTaker timer1("emerge load", &emerge_load_time);
4528                         MapNode n = m_map->getNode(a.MinEdge + p);
4529                         m_data[i] = n;
4530                         m_flags[i] = 0;
4531                 }
4532                 catch(InvalidPositionException &e)
4533                 {
4534                         m_flags[i] = VOXELFLAG_INEXISTENT;
4535                 }
4536         }
4537 }
4538 #endif
4539
4540
4541 /*
4542         SUGG: Add an option to only update eg. water and air nodes.
4543               This will make it interfere less with important stuff if
4544                   run on background.
4545 */
4546 void MapVoxelManipulator::blitBack
4547                 (core::map<v3s16, MapBlock*> & modified_blocks)
4548 {
4549         if(m_area.getExtent() == v3s16(0,0,0))
4550                 return;
4551         
4552         //TimeTaker timer1("blitBack");
4553
4554         /*dstream<<"blitBack(): m_loaded_blocks.size()="
4555                         <<m_loaded_blocks.size()<<std::endl;*/
4556         
4557         /*
4558                 Initialize block cache
4559         */
4560         v3s16 blockpos_last;
4561         MapBlock *block = NULL;
4562         bool block_checked_in_modified = false;
4563
4564         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4565         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4566         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4567         {
4568                 v3s16 p(x,y,z);
4569
4570                 u8 f = m_flags[m_area.index(p)];
4571                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4572                         continue;
4573
4574                 MapNode &n = m_data[m_area.index(p)];
4575                         
4576                 v3s16 blockpos = getNodeBlockPos(p);
4577                 
4578                 try
4579                 {
4580                         // Get block
4581                         if(block == NULL || blockpos != blockpos_last){
4582                                 block = m_map->getBlockNoCreate(blockpos);
4583                                 blockpos_last = blockpos;
4584                                 block_checked_in_modified = false;
4585                         }
4586                         
4587                         // Calculate relative position in block
4588                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4589
4590                         // Don't continue if nothing has changed here
4591                         if(block->getNode(relpos) == n)
4592                                 continue;
4593
4594                         //m_map->setNode(m_area.MinEdge + p, n);
4595                         block->setNode(relpos, n);
4596                         
4597                         /*
4598                                 Make sure block is in modified_blocks
4599                         */
4600                         if(block_checked_in_modified == false)
4601                         {
4602                                 modified_blocks[blockpos] = block;
4603                                 block_checked_in_modified = true;
4604                         }
4605                 }
4606                 catch(InvalidPositionException &e)
4607                 {
4608                 }
4609         }
4610 }
4611
4612 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4613                 MapVoxelManipulator(map)
4614 {
4615 }
4616
4617 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4618 {
4619 }
4620
4621 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4622 {
4623         // Just create the area to avoid segfaults
4624         VoxelManipulator::emerge(a, caller_id);
4625
4626         /*
4627                 Just create the area to avoid segfaults
4628         */
4629         /*addArea(a);
4630         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4631         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4632         for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
4633         {
4634                 s32 i = m_area.index(x,y,z);
4635                 // Don't touch nodes that have already been loaded
4636                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
4637                         continue;
4638                 m_flags[i] = VOXELFLAG_INEXISTENT;
4639         }*/
4640 }
4641
4642 void ManualMapVoxelManipulator::initialEmerge(
4643                 v3s16 blockpos_min, v3s16 blockpos_max)
4644 {
4645         TimeTaker timer1("emerge", &emerge_time);
4646
4647         // Units of these are MapBlocks
4648         v3s16 p_min = blockpos_min;
4649         v3s16 p_max = blockpos_max;
4650
4651         VoxelArea block_area_nodes
4652                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4653
4654         addArea(block_area_nodes);
4655
4656         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4657         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4658         for(s32 x=p_min.X; x<=p_max.X; x++)
4659         {
4660                 v3s16 p(x,y,z);
4661                 core::map<v3s16, bool>::Node *n;
4662                 n = m_loaded_blocks.find(p);
4663                 if(n != NULL)
4664                         continue;
4665                 
4666                 bool block_data_inexistent = false;
4667                 try
4668                 {
4669                         TimeTaker timer1("emerge load", &emerge_load_time);
4670
4671                         MapBlock *block = m_map->getBlockNoCreate(p);
4672                         if(block->isDummy())
4673                                 block_data_inexistent = true;
4674                         else
4675                                 block->copyTo(*this);
4676                 }
4677                 catch(InvalidPositionException &e)
4678                 {
4679                         block_data_inexistent = true;
4680                 }
4681
4682                 if(block_data_inexistent)
4683                 {
4684                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4685                         // Fill with VOXELFLAG_INEXISTENT
4686                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4687                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4688                         {
4689                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4690                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4691                         }
4692                 }
4693
4694                 m_loaded_blocks.insert(p, true);
4695         }
4696 }
4697
4698 //END