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