]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
Faster lighting at map generation time
[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
29 /*
30         Map
31 */
32
33 Map::Map(std::ostream &dout):
34         m_dout(dout),
35         m_camera_position(0,0,0),
36         m_camera_direction(0,0,1),
37         m_sector_cache(NULL),
38         m_hwrapper(this)
39 {
40         m_sector_mutex.Init();
41         m_camera_mutex.Init();
42         assert(m_sector_mutex.IsInitialized());
43         assert(m_camera_mutex.IsInitialized());
44         
45         // Get this so that the player can stay on it at first
46         //getSector(v2s16(0,0));
47 }
48
49 Map::~Map()
50 {
51         /*
52                 Stop updater thread
53         */
54         /*updater.setRun(false);
55         while(updater.IsRunning())
56                 sleep_s(1);*/
57
58         /*
59                 Free all MapSectors.
60         */
61         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
62         for(; i.atEnd() == false; i++)
63         {
64                 MapSector *sector = i.getNode()->getValue();
65                 delete sector;
66         }
67 }
68
69 MapSector * Map::getSectorNoGenerate(v2s16 p)
70 {
71         JMutexAutoLock lock(m_sector_mutex);
72
73         if(m_sector_cache != NULL && p == m_sector_cache_p){
74                 MapSector * sector = m_sector_cache;
75                 // Reset inactivity timer
76                 sector->usage_timer = 0.0;
77                 return sector;
78         }
79         
80         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
81         // If sector doesn't exist, throw an exception
82         if(n == NULL)
83         {
84                 throw InvalidPositionException();
85         }
86         
87         MapSector *sector = n->getValue();
88         
89         // Cache the last result
90         m_sector_cache_p = p;
91         m_sector_cache = sector;
92
93         //MapSector * ref(sector);
94         
95         // Reset inactivity timer
96         sector->usage_timer = 0.0;
97         return sector;
98 }
99
100 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
101 {       
102         v2s16 p2d(p3d.X, p3d.Z);
103         MapSector * sector = getSectorNoGenerate(p2d);
104
105         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
106
107         return block;
108 }
109
110 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
111 {
112         try
113         {
114                 v2s16 p2d(p3d.X, p3d.Z);
115                 MapSector * sector = getSectorNoGenerate(p2d);
116                 MapBlock *block = sector->getBlockNoCreate(p3d.Y);
117                 return block;
118         }
119         catch(InvalidPositionException &e)
120         {
121                 return NULL;
122         }
123 }
124
125 f32 Map::getGroundHeight(v2s16 p, bool generate)
126 {
127         try{
128                 v2s16 sectorpos = getNodeSectorPos(p);
129                 MapSector * sref = getSectorNoGenerate(sectorpos);
130                 v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
131                 f32 y = sref->getGroundHeight(relpos);
132                 return y;
133         }
134         catch(InvalidPositionException &e)
135         {
136                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
137         }
138 }
139
140 void Map::setGroundHeight(v2s16 p, f32 y, bool generate)
141 {
142         /*m_dout<<DTIME<<"Map::setGroundHeight(("
143                         <<p.X<<","<<p.Y
144                         <<"), "<<y<<")"<<std::endl;*/
145         v2s16 sectorpos = getNodeSectorPos(p);
146         MapSector * sref = getSectorNoGenerate(sectorpos);
147         v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
148         //sref->mutex.Lock();
149         sref->setGroundHeight(relpos, y);
150         //sref->mutex.Unlock();
151 }
152
153 bool Map::isNodeUnderground(v3s16 p)
154 {
155         v3s16 blockpos = getNodeBlockPos(p);
156         try{
157                 MapBlock * block = getBlockNoCreate(blockpos);
158                 return block->getIsUnderground();
159         }
160         catch(InvalidPositionException &e)
161         {
162                 return false;
163         }
164 }
165
166 /*
167         Goes recursively through the neighbours of the node.
168
169         Alters only transparent nodes.
170
171         If the lighting of the neighbour is lower than the lighting of
172         the node was (before changing it to 0 at the step before), the
173         lighting of the neighbour is set to 0 and then the same stuff
174         repeats for the neighbour.
175
176         The ending nodes of the routine are stored in light_sources.
177         This is useful when a light is removed. In such case, this
178         routine can be called for the light node and then again for
179         light_sources to re-light the area without the removed light.
180
181         values of from_nodes are lighting values.
182 */
183 void Map::unspreadLight(enum LightBank bank,
184                 core::map<v3s16, u8> & from_nodes,
185                 core::map<v3s16, bool> & light_sources,
186                 core::map<v3s16, MapBlock*>  & modified_blocks)
187 {
188         v3s16 dirs[6] = {
189                 v3s16(0,0,1), // back
190                 v3s16(0,1,0), // top
191                 v3s16(1,0,0), // right
192                 v3s16(0,0,-1), // front
193                 v3s16(0,-1,0), // bottom
194                 v3s16(-1,0,0), // left
195         };
196         
197         if(from_nodes.size() == 0)
198                 return;
199         
200         u32 blockchangecount = 0;
201
202         core::map<v3s16, u8> unlighted_nodes;
203         core::map<v3s16, u8>::Iterator j;
204         j = from_nodes.getIterator();
205
206         /*
207                 Initialize block cache
208         */
209         v3s16 blockpos_last;
210         MapBlock *block = NULL;
211         // Cache this a bit, too
212         bool block_checked_in_modified = false;
213         
214         for(; j.atEnd() == false; j++)
215         {
216                 v3s16 pos = j.getNode()->getKey();
217                 v3s16 blockpos = getNodeBlockPos(pos);
218                 
219                 // Only fetch a new block if the block position has changed
220                 try{
221                         if(block == NULL || blockpos != blockpos_last){
222                                 block = getBlockNoCreate(blockpos);
223                                 blockpos_last = blockpos;
224
225                                 block_checked_in_modified = false;
226                                 blockchangecount++;
227                         }
228                 }
229                 catch(InvalidPositionException &e)
230                 {
231                         continue;
232                 }
233
234                 if(block->isDummy())
235                         continue;
236
237                 // Calculate relative position in block
238                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
239
240                 // Get node straight from the block
241                 MapNode n = block->getNode(relpos);
242                 
243                 u8 oldlight = j.getNode()->getValue();
244                 
245                 // Loop through 6 neighbors
246                 for(u16 i=0; i<6; i++)
247                 {
248                         // Get the position of the neighbor node
249                         v3s16 n2pos = pos + dirs[i];
250                         
251                         // Get the block where the node is located
252                         v3s16 blockpos = getNodeBlockPos(n2pos);
253
254                         try
255                         {
256                                 // Only fetch a new block if the block position has changed
257                                 try{
258                                         if(block == NULL || blockpos != blockpos_last){
259                                                 block = getBlockNoCreate(blockpos);
260                                                 blockpos_last = blockpos;
261
262                                                 block_checked_in_modified = false;
263                                                 blockchangecount++;
264                                         }
265                                 }
266                                 catch(InvalidPositionException &e)
267                                 {
268                                         continue;
269                                 }
270                                 
271                                 // Calculate relative position in block
272                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
273                                 // Get node straight from the block
274                                 MapNode n2 = block->getNode(relpos);
275                                 
276                                 bool changed = false;
277
278                                 //TODO: Optimize output by optimizing light_sources?
279
280                                 /*
281                                         If the neighbor is dimmer than what was specified
282                                         as oldlight (the light of the previous node)
283                                 */
284                                 if(n2.getLight(bank) < oldlight)
285                                 {
286                                         /*
287                                                 And the neighbor is transparent and it has some light
288                                         */
289                                         if(n2.light_propagates() && n2.getLight(bank) != 0)
290                                         {
291                                                 /*
292                                                         Set light to 0 and add to queue
293                                                 */
294
295                                                 u8 current_light = n2.getLight(bank);
296                                                 n2.setLight(bank, 0);
297                                                 block->setNode(relpos, n2);
298
299                                                 unlighted_nodes.insert(n2pos, current_light);
300                                                 changed = true;
301
302                                                 /*
303                                                         Remove from light_sources if it is there
304                                                         NOTE: This doesn't happen nearly at all
305                                                 */
306                                                 /*if(light_sources.find(n2pos))
307                                                 {
308                                                         std::cout<<"Removed from light_sources"<<std::endl;
309                                                         light_sources.remove(n2pos);
310                                                 }*/
311                                         }
312                                         
313                                         /*// DEBUG
314                                         if(light_sources.find(n2pos) != NULL)
315                                                 light_sources.remove(n2pos);*/
316                                 }
317                                 else{
318                                         light_sources.insert(n2pos, true);
319                                 }
320
321                                 // Add to modified_blocks
322                                 if(changed == true && block_checked_in_modified == false)
323                                 {
324                                         // If the block is not found in modified_blocks, add.
325                                         if(modified_blocks.find(blockpos) == NULL)
326                                         {
327                                                 modified_blocks.insert(blockpos, block);
328                                         }
329                                         block_checked_in_modified = true;
330                                 }
331                         }
332                         catch(InvalidPositionException &e)
333                         {
334                                 continue;
335                         }
336                 }
337         }
338
339         /*dstream<<"unspreadLight(): Changed block "
340                         <<blockchangecount<<" times"
341                         <<" for "<<from_nodes.size()<<" nodes"
342                         <<std::endl;*/
343         
344         if(unlighted_nodes.size() > 0)
345                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
346 }
347
348 /*
349         A single-node wrapper of the above
350 */
351 void Map::unLightNeighbors(enum LightBank bank,
352                 v3s16 pos, u8 lightwas,
353                 core::map<v3s16, bool> & light_sources,
354                 core::map<v3s16, MapBlock*>  & modified_blocks)
355 {
356         core::map<v3s16, u8> from_nodes;
357         from_nodes.insert(pos, lightwas);
358
359         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
360 }
361
362 /*
363         Lights neighbors of from_nodes, collects all them and then
364         goes on recursively.
365 */
366 void Map::spreadLight(enum LightBank bank,
367                 core::map<v3s16, bool> & from_nodes,
368                 core::map<v3s16, MapBlock*> & modified_blocks)
369 {
370         const v3s16 dirs[6] = {
371                 v3s16(0,0,1), // back
372                 v3s16(0,1,0), // top
373                 v3s16(1,0,0), // right
374                 v3s16(0,0,-1), // front
375                 v3s16(0,-1,0), // bottom
376                 v3s16(-1,0,0), // left
377         };
378
379         if(from_nodes.size() == 0)
380                 return;
381         
382         u32 blockchangecount = 0;
383
384         core::map<v3s16, bool> lighted_nodes;
385         core::map<v3s16, bool>::Iterator j;
386         j = from_nodes.getIterator();
387
388         /*
389                 Initialize block cache
390         */
391         v3s16 blockpos_last;
392         MapBlock *block = NULL;
393         // Cache this a bit, too
394         bool block_checked_in_modified = false;
395         
396         for(; j.atEnd() == false; j++)
397         //for(; j != from_nodes.end(); j++)
398         {
399                 v3s16 pos = j.getNode()->getKey();
400                 //v3s16 pos = *j;
401                 //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
402                 v3s16 blockpos = getNodeBlockPos(pos);
403                 
404                 // Only fetch a new block if the block position has changed
405                 try{
406                         if(block == NULL || blockpos != blockpos_last){
407                                 block = getBlockNoCreate(blockpos);
408                                 blockpos_last = blockpos;
409
410                                 block_checked_in_modified = false;
411                                 blockchangecount++;
412                         }
413                 }
414                 catch(InvalidPositionException &e)
415                 {
416                         continue;
417                 }
418
419                 if(block->isDummy())
420                         continue;
421
422                 // Calculate relative position in block
423                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
424
425                 // Get node straight from the block
426                 MapNode n = block->getNode(relpos);
427
428                 u8 oldlight = n.getLight(bank);
429                 u8 newlight = diminish_light(oldlight);
430
431                 // Loop through 6 neighbors
432                 for(u16 i=0; i<6; i++){
433                         // Get the position of the neighbor node
434                         v3s16 n2pos = pos + dirs[i];
435                         
436                         // Get the block where the node is located
437                         v3s16 blockpos = getNodeBlockPos(n2pos);
438
439                         try
440                         {
441                                 // Only fetch a new block if the block position has changed
442                                 try{
443                                         if(block == NULL || blockpos != blockpos_last){
444                                                 block = getBlockNoCreate(blockpos);
445                                                 blockpos_last = blockpos;
446
447                                                 block_checked_in_modified = false;
448                                                 blockchangecount++;
449                                         }
450                                 }
451                                 catch(InvalidPositionException &e)
452                                 {
453                                         continue;
454                                 }
455                                 
456                                 // Calculate relative position in block
457                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
458                                 // Get node straight from the block
459                                 MapNode n2 = block->getNode(relpos);
460                                 
461                                 bool changed = false;
462                                 /*
463                                         If the neighbor is brighter than the current node,
464                                         add to list (it will light up this node on its turn)
465                                 */
466                                 if(n2.getLight(bank) > undiminish_light(oldlight))
467                                 {
468                                         lighted_nodes.insert(n2pos, true);
469                                         //lighted_nodes.push_back(n2pos);
470                                         changed = true;
471                                 }
472                                 /*
473                                         If the neighbor is dimmer than how much light this node
474                                         would spread on it, add to list
475                                 */
476                                 if(n2.getLight(bank) < newlight)
477                                 {
478                                         if(n2.light_propagates())
479                                         {
480                                                 n2.setLight(bank, newlight);
481                                                 block->setNode(relpos, n2);
482                                                 lighted_nodes.insert(n2pos, true);
483                                                 //lighted_nodes.push_back(n2pos);
484                                                 changed = true;
485                                         }
486                                 }
487
488                                 // Add to modified_blocks
489                                 if(changed == true && block_checked_in_modified == false)
490                                 {
491                                         // If the block is not found in modified_blocks, add.
492                                         if(modified_blocks.find(blockpos) == NULL)
493                                         {
494                                                 modified_blocks.insert(blockpos, block);
495                                         }
496                                         block_checked_in_modified = true;
497                                 }
498                         }
499                         catch(InvalidPositionException &e)
500                         {
501                                 continue;
502                         }
503                 }
504         }
505
506         /*dstream<<"spreadLight(): Changed block "
507                         <<blockchangecount<<" times"
508                         <<" for "<<from_nodes.size()<<" nodes"
509                         <<std::endl;*/
510         
511         if(lighted_nodes.size() > 0)
512                 spreadLight(bank, lighted_nodes, modified_blocks);
513 }
514
515 /*
516         A single-node source variation of the above.
517 */
518 void Map::lightNeighbors(enum LightBank bank,
519                 v3s16 pos,
520                 core::map<v3s16, MapBlock*> & modified_blocks)
521 {
522         core::map<v3s16, bool> from_nodes;
523         from_nodes.insert(pos, true);
524         spreadLight(bank, from_nodes, modified_blocks);
525 }
526
527 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
528 {
529         v3s16 dirs[6] = {
530                 v3s16(0,0,1), // back
531                 v3s16(0,1,0), // top
532                 v3s16(1,0,0), // right
533                 v3s16(0,0,-1), // front
534                 v3s16(0,-1,0), // bottom
535                 v3s16(-1,0,0), // left
536         };
537         
538         u8 brightest_light = 0;
539         v3s16 brightest_pos(0,0,0);
540         bool found_something = false;
541
542         // Loop through 6 neighbors
543         for(u16 i=0; i<6; i++){
544                 // Get the position of the neighbor node
545                 v3s16 n2pos = p + dirs[i];
546                 MapNode n2;
547                 try{
548                         n2 = getNode(n2pos);
549                 }
550                 catch(InvalidPositionException &e)
551                 {
552                         continue;
553                 }
554                 if(n2.getLight(bank) > brightest_light || found_something == false){
555                         brightest_light = n2.getLight(bank);
556                         brightest_pos = n2pos;
557                         found_something = true;
558                 }
559         }
560
561         if(found_something == false)
562                 throw InvalidPositionException();
563                 
564         return brightest_pos;
565 }
566
567 /*
568         Propagates sunlight down from a node.
569         Starting point gets sunlight.
570
571         Returns the lowest y value of where the sunlight went.
572
573         Mud is turned into grass in where the sunlight stops.
574 */
575 s16 Map::propagateSunlight(v3s16 start,
576                 core::map<v3s16, MapBlock*> & modified_blocks)
577 {
578         s16 y = start.Y;
579         for(; ; y--)
580         {
581                 v3s16 pos(start.X, y, start.Z);
582                 
583                 v3s16 blockpos = getNodeBlockPos(pos);
584                 MapBlock *block;
585                 try{
586                         block = getBlockNoCreate(blockpos);
587                 }
588                 catch(InvalidPositionException &e)
589                 {
590                         break;
591                 }
592
593                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
594                 MapNode n = block->getNode(relpos);
595
596                 if(n.sunlight_propagates())
597                 {
598                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
599                         block->setNode(relpos, n);
600
601                         modified_blocks.insert(blockpos, block);
602                 }
603                 else
604                 {
605                         // Turn mud into grass
606                         if(n.d == CONTENT_MUD)
607                         {
608                                 n.d = CONTENT_GRASS;
609                                 block->setNode(relpos, n);
610                                 modified_blocks.insert(blockpos, block);
611                         }
612
613                         // Sunlight goes no further
614                         break;
615                 }
616         }
617         return y + 1;
618 }
619
620 void Map::updateLighting(enum LightBank bank,
621                 core::map<v3s16, MapBlock*> & a_blocks,
622                 core::map<v3s16, MapBlock*> & modified_blocks)
623 {
624         /*m_dout<<DTIME<<"Map::updateLighting(): "
625                         <<a_blocks.size()<<" blocks."<<std::endl;*/
626         
627         //TimeTaker timer("updateLighting");
628         
629         // For debugging
630         bool debug=true;
631
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                         list_baseheight->addPoint(p, Attribute(baseheight));
1839                         list_randmax->addPoint(p, Attribute(randmax));
1840                         list_randfactor->addPoint(p, Attribute(randfactor));
1841                 }
1842
1843                 /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(5));
1844                 list_randmax->addPoint(v3s16(0,0,0), Attribute(20));
1845                 list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.6));*/
1846
1847                 // Easy spawn point
1848                 /*list_baseheight->addPoint(v3s16(0,0,0), Attribute(0));
1849                 list_randmax->addPoint(v3s16(0,0,0), Attribute(10));
1850                 list_randfactor->addPoint(v3s16(0,0,0), Attribute(0.65));*/
1851         }
1852
1853         /*
1854                 Try to load map; if not found, create a new one.
1855         */
1856
1857         m_savedir = savedir;
1858         m_map_saving_enabled = false;
1859         
1860         try
1861         {
1862                 // If directory exists, check contents and load if possible
1863                 if(fs::PathExists(m_savedir))
1864                 {
1865                         // If directory is empty, it is safe to save into it.
1866                         if(fs::GetDirListing(m_savedir).size() == 0)
1867                         {
1868                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1869                                                 <<std::endl;
1870                                 m_map_saving_enabled = true;
1871                         }
1872                         else
1873                         {
1874                                 // Load master heightmap
1875                                 loadMasterHeightmap();
1876                                 
1877                                 // Load sector (0,0) and throw and exception on fail
1878                                 if(loadSectorFull(v2s16(0,0)) == false)
1879                                         throw LoadError("Failed to load sector (0,0)");
1880
1881                                 dstream<<DTIME<<"Server: Successfully loaded master "
1882                                                 "heightmap and sector (0,0) from "<<savedir<<
1883                                                 ", assuming valid save directory."
1884                                                 <<std::endl;
1885
1886                                 m_map_saving_enabled = true;
1887                                 // Map loaded, not creating new one
1888                                 return;
1889                         }
1890                 }
1891                 // If directory doesn't exist, it is safe to save to it
1892                 else{
1893                         m_map_saving_enabled = true;
1894                 }
1895         }
1896         catch(std::exception &e)
1897         {
1898                 dstream<<DTIME<<"Server: Failed to load map from "<<savedir
1899                                 <<", exception: "<<e.what()<<std::endl;
1900                 dstream<<DTIME<<"Please remove the map or fix it."<<std::endl;
1901                 dstream<<DTIME<<"WARNING: Map saving will be disabled."<<std::endl;
1902         }
1903
1904         dstream<<DTIME<<"Initializing new map."<<std::endl;
1905         
1906         // Create master heightmap
1907         /*ValueGenerator *maxgen =
1908                         ValueGenerator::deSerialize(hmp.randmax);
1909         ValueGenerator *factorgen =
1910                         ValueGenerator::deSerialize(hmp.randfactor);
1911         ValueGenerator *basegen =
1912                         ValueGenerator::deSerialize(hmp.base);
1913         m_heightmap = new UnlimitedHeightmap
1914                         (hmp.blocksize, maxgen, factorgen, basegen, &m_padb);*/
1915
1916         /*m_heightmap = new UnlimitedHeightmap
1917                         (hmp.blocksize, &m_padb);*/
1918
1919         m_heightmap = new UnlimitedHeightmap
1920                         (32, &m_padb);
1921         
1922         // Set map parameters
1923         m_params = mp;
1924         
1925         // Create zero sector
1926         emergeSector(v2s16(0,0));
1927
1928         // Initially write whole map
1929         save(false);
1930 }
1931
1932 ServerMap::~ServerMap()
1933 {
1934         try
1935         {
1936                 if(m_map_saving_enabled)
1937                 {
1938                         //save(false);
1939                         // Save only changed parts
1940                         save(true);
1941                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1942                 }
1943                 else
1944                 {
1945                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1946                 }
1947         }
1948         catch(std::exception &e)
1949         {
1950                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1951                                 <<", exception: "<<e.what()<<std::endl;
1952         }
1953         
1954         if(m_heightmap != NULL)
1955                 delete m_heightmap;
1956 }
1957
1958 MapSector * ServerMap::emergeSector(v2s16 p2d)
1959 {
1960         DSTACK("%s: p2d=(%d,%d)",
1961                         __FUNCTION_NAME,
1962                         p2d.X, p2d.Y);
1963         // Check that it doesn't exist already
1964         try{
1965                 return getSectorNoGenerate(p2d);
1966         }
1967         catch(InvalidPositionException &e)
1968         {
1969         }
1970         
1971         /*
1972                 Try to load the sector from disk.
1973         */
1974         if(loadSectorFull(p2d) == true)
1975         {
1976                 return getSectorNoGenerate(p2d);
1977         }
1978
1979         /*
1980                 If there is no master heightmap, throw.
1981         */
1982         if(m_heightmap == NULL)
1983         {
1984                 throw InvalidPositionException("emergeSector(): no heightmap");
1985         }
1986
1987         /*
1988                 Do not generate over-limit
1989         */
1990         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1991         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1992         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1993         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
1994                 throw InvalidPositionException("emergeSector(): pos. over limit");
1995
1996         /*
1997                 Generate sector and heightmaps
1998         */
1999         
2000         // Number of heightmaps in sector in each direction
2001         u16 hm_split = SECTOR_HEIGHTMAP_SPLIT;
2002
2003         // Heightmap side width
2004         s16 hm_d = MAP_BLOCKSIZE / hm_split;
2005
2006         ServerMapSector *sector = new ServerMapSector(this, p2d, hm_split);
2007         
2008         // Sector position on map in nodes
2009         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2010
2011         /*dstream<<"Generating sector ("<<p2d.X<<","<<p2d.Y<<")"
2012                         " heightmaps and objects"<<std::endl;*/
2013         
2014         /*
2015                 Calculate some information about local properties
2016         */
2017         
2018         v2s16 mhm_p = p2d * hm_split;
2019         f32 corners[4] = {
2020                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)*hm_split),
2021                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)*hm_split),
2022                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)*hm_split),
2023                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)*hm_split),
2024         };
2025         
2026         float avgheight = (corners[0]+corners[1]+corners[2]+corners[3])/4.0;
2027         float avgslope = 0.0;
2028         avgslope += fabs(avgheight - corners[0]);
2029         avgslope += fabs(avgheight - corners[1]);
2030         avgslope += fabs(avgheight - corners[2]);
2031         avgslope += fabs(avgheight - corners[3]);
2032         avgslope /= 4.0;
2033         avgslope /= MAP_BLOCKSIZE;
2034         //dstream<<"avgslope="<<avgslope<<std::endl;
2035
2036         float pitness = 0.0;
2037         v2f32 a;
2038         a = m_heightmap->getSlope(p2d+v2s16(0,0));
2039         pitness += -a.X;
2040         pitness += -a.Y;
2041         a = m_heightmap->getSlope(p2d+v2s16(0,1));
2042         pitness += -a.X;
2043         pitness += a.Y;
2044         a = m_heightmap->getSlope(p2d+v2s16(1,1));
2045         pitness += a.X;
2046         pitness += a.Y;
2047         a = m_heightmap->getSlope(p2d+v2s16(1,0));
2048         pitness += a.X;
2049         pitness += -a.Y;
2050         pitness /= 4.0;
2051         pitness /= MAP_BLOCKSIZE;
2052         //dstream<<"pitness="<<pitness<<std::endl;
2053
2054         /*
2055                 Get local attributes
2056         */
2057         
2058         float local_plants_amount = 0.0;
2059         {
2060                 //dstream<<"emergeSector(): Reading point attribute lists"<<std::endl;
2061                 //TimeTaker attrtimer("emergeSector() attribute fetch");
2062                 
2063                 // Get plant amount from attributes
2064                 PointAttributeList *palist = m_padb.getList("plants_amount");
2065                 assert(palist);
2066                 /*local_plants_amount =
2067                                 palist->getNearAttr(nodepos2d).getFloat();*/
2068                 local_plants_amount =
2069                                 palist->getInterpolatedFloat(nodepos2d);
2070         }
2071
2072         /*
2073                 Generate sector heightmap
2074         */
2075
2076         // Loop through sub-heightmaps
2077         for(s16 y=0; y<hm_split; y++)
2078         for(s16 x=0; x<hm_split; x++)
2079         {
2080                 v2s16 p_in_sector = v2s16(x,y);
2081                 v2s16 mhm_p = p2d * hm_split + p_in_sector;
2082                 f32 corners[4] = {
2083                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)),
2084                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)),
2085                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)),
2086                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)),
2087                 };
2088
2089                 /*dstream<<"p_in_sector=("<<p_in_sector.X<<","<<p_in_sector.Y<<")"
2090                                 <<" mhm_p=("<<mhm_p.X<<","<<mhm_p.Y<<")"
2091                                 <<std::endl;*/
2092
2093                 FixedHeightmap *hm = new FixedHeightmap(&m_hwrapper,
2094                                 mhm_p, hm_d);
2095                 sector->setHeightmap(p_in_sector, hm);
2096
2097                 //TODO: Make these values configurable
2098                 //hm->generateContinued(0.0, 0.0, corners);
2099                 //hm->generateContinued(0.25, 0.2, corners);
2100                 //hm->generateContinued(0.5, 0.2, corners);
2101                 //hm->generateContinued(1.0, 0.2, corners);
2102                 //hm->generateContinued(2.0, 0.2, corners);
2103                 //hm->generateContinued(2.0 * avgslope, 0.5, corners);
2104                 hm->generateContinued(avgslope * MAP_BLOCKSIZE/8, 0.5, corners);
2105
2106                 //hm->print();
2107         }
2108
2109         /*
2110                 Generate objects
2111         */
2112         
2113         core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
2114         sector->setObjects(objects);
2115
2116         float area = MAP_BLOCKSIZE * MAP_BLOCKSIZE;
2117
2118         /*
2119                 Plant some trees if there is not much slope
2120         */
2121         {
2122                 // Avgslope is the derivative of a hill
2123                 //float t = avgslope * avgslope;
2124                 float t = avgslope;
2125                 float a = area/16 * m_params.plants_amount * local_plants_amount;
2126                 u32 tree_max;
2127                 //float something = 0.17*0.17;
2128                 float something = 0.3;
2129                 if(t > something)
2130                         tree_max = a / (t/something);
2131                 else
2132                         tree_max = a;
2133                 
2134                 u32 count = (myrand()%(tree_max+1));
2135                 //u32 count = tree_max;
2136                 for(u32 i=0; i<count; i++)
2137                 {
2138                         s16 x = (myrand()%(MAP_BLOCKSIZE-2))+1;
2139                         s16 z = (myrand()%(MAP_BLOCKSIZE-2))+1;
2140                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
2141                         if(y < WATER_LEVEL)
2142                                 continue;
2143                         objects->insert(v3s16(x, y, z),
2144                                         SECTOR_OBJECT_TREE_1);
2145                 }
2146         }
2147         /*
2148                 Plant some bushes if sector is pit-like
2149         */
2150         {
2151                 // Pitness usually goes at around -0.5...0.5
2152                 u32 bush_max = 0;
2153                 u32 a = area/16 * 3.0 * m_params.plants_amount * local_plants_amount;
2154                 if(pitness > 0)
2155                         bush_max = (pitness*a*4);
2156                 if(bush_max > a)
2157                         bush_max = a;
2158                 u32 count = (myrand()%(bush_max+1));
2159                 for(u32 i=0; i<count; i++)
2160                 {
2161                         s16 x = myrand()%(MAP_BLOCKSIZE-0)+0;
2162                         s16 z = myrand()%(MAP_BLOCKSIZE-0)+0;
2163                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
2164                         if(y < WATER_LEVEL)
2165                                 continue;
2166                         objects->insert(v3s16(x, y, z),
2167                                         SECTOR_OBJECT_BUSH_1);
2168                 }
2169         }
2170         /*
2171                 Add ravine (randomly)
2172         */
2173         if(m_params.ravines_amount > 0.001)
2174         {
2175                 if(myrand()%(s32)(200.0 / m_params.ravines_amount) == 0)
2176                 {
2177                         s16 s = 6;
2178                         s16 x = myrand()%(MAP_BLOCKSIZE-s*2-1)+s;
2179                         s16 z = myrand()%(MAP_BLOCKSIZE-s*2-1)+s;
2180                         /*s16 x = 8;
2181                         s16 z = 8;*/
2182                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
2183                         objects->insert(v3s16(x, y, z),
2184                                         SECTOR_OBJECT_RAVINE);
2185                 }
2186         }
2187
2188         /*
2189                 Insert to container
2190         */
2191         JMutexAutoLock lock(m_sector_mutex);
2192         m_sectors.insert(p2d, sector);
2193         
2194         return sector;
2195 }
2196
2197 MapBlock * ServerMap::emergeBlock(
2198                 v3s16 p,
2199                 bool only_from_disk,
2200                 core::map<v3s16, MapBlock*> &changed_blocks,
2201                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
2202 )
2203 {
2204         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
2205                         __FUNCTION_NAME,
2206                         p.X, p.Y, p.Z, only_from_disk);
2207                         
2208         /*dstream<<"ServerMap::emergeBlock(): "
2209                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2210                         <<", only_from_disk="<<only_from_disk<<std::endl;*/
2211         v2s16 p2d(p.X, p.Z);
2212         s16 block_y = p.Y;
2213         /*
2214                 This will create or load a sector if not found in memory.
2215                 If block exists on disk, it will be loaded.
2216
2217                 NOTE: On old save formats, this will be slow, as it generates
2218                       lighting on blocks for them.
2219         */
2220         ServerMapSector *sector = (ServerMapSector*)emergeSector(p2d);
2221         assert(sector->getId() == MAPSECTOR_SERVER);
2222
2223         // Try to get a block from the sector
2224         MapBlock *block = NULL;
2225         bool not_on_disk = false;
2226         try{
2227                 block = sector->getBlockNoCreate(block_y);
2228                 if(block->isDummy() == true)
2229                         not_on_disk = true;
2230                 else
2231                         return block;
2232         }
2233         catch(InvalidPositionException &e)
2234         {
2235                 not_on_disk = true;
2236         }
2237         
2238         /*
2239                 If block was not found on disk and not going to generate a
2240                 new one, make sure there is a dummy block in place.
2241         */
2242         if(not_on_disk && only_from_disk)
2243         {
2244                 if(block == NULL)
2245                 {
2246                         // Create dummy block
2247                         block = new MapBlock(this, p, true);
2248
2249                         // Add block to sector
2250                         sector->insertBlock(block);
2251                 }
2252                 // Done.
2253                 return block;
2254         }
2255
2256         //dstream<<"Not found on disk, generating."<<std::endl;
2257         // 0ms
2258         //TimeTaker("emergeBlock() generate");
2259
2260         /*
2261                 Do not generate over-limit
2262         */
2263         if(blockpos_over_limit(p))
2264                 throw InvalidPositionException("emergeBlock(): pos. over limit");
2265
2266         /*
2267                 OK; Not found.
2268
2269                 Go on generating the block.
2270
2271                 TODO: If a dungeon gets generated so that it's side gets
2272                       revealed to the outside air, the lighting should be
2273                           recalculated.
2274         */
2275         
2276         /*
2277                 If block doesn't exist, create one.
2278                 If it exists, it is a dummy. In that case unDummify() it.
2279
2280                 NOTE: This already sets the map as the parent of the block
2281         */
2282         if(block == NULL)
2283         {
2284                 block = sector->createBlankBlockNoInsert(block_y);
2285         }
2286         else
2287         {
2288                 // Remove the block so that nobody can get a half-generated one.
2289                 sector->removeBlock(block);
2290                 // Allocate the block to contain the generated data
2291                 block->unDummify();
2292         }
2293         
2294         /*u8 water_material = CONTENT_WATER;
2295         if(g_settings.getBool("endless_water"))
2296                 water_material = CONTENT_WATERSOURCE;*/
2297         u8 water_material = CONTENT_WATERSOURCE;
2298         
2299         s32 lowest_ground_y = 32767;
2300         s32 highest_ground_y = -32768;
2301         
2302         // DEBUG
2303         //sector->printHeightmaps();
2304
2305         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2306         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2307         {
2308                 //dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
2309
2310                 float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
2311                 //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
2312                 if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE)
2313                 {
2314                         dstream<<"WARNING: Surface height not found in sector "
2315                                         "for block that is being emerged"<<std::endl;
2316                         surface_y_f = 0.0;
2317                 }
2318
2319                 s16 surface_y = surface_y_f;
2320                 //avg_ground_y += surface_y;
2321                 if(surface_y < lowest_ground_y)
2322                         lowest_ground_y = surface_y;
2323                 if(surface_y > highest_ground_y)
2324                         highest_ground_y = surface_y;
2325
2326                 s32 surface_depth = 0;
2327                 
2328                 float slope = sector->getSlope(v2s16(x0,z0)).getLength();
2329                 
2330                 //float min_slope = 0.45;
2331                 //float max_slope = 0.85;
2332                 float min_slope = 0.60;
2333                 float max_slope = 1.20;
2334                 float min_slope_depth = 5.0;
2335                 float max_slope_depth = 0;
2336
2337                 if(slope < min_slope)
2338                         surface_depth = min_slope_depth;
2339                 else if(slope > max_slope)
2340                         surface_depth = max_slope_depth;
2341                 else
2342                         surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
2343
2344                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2345                 {
2346                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
2347                         MapNode n;
2348                         /*
2349                                 Calculate lighting
2350                                 
2351                                 NOTE: If there are some man-made structures above the
2352                                 newly created block, they won't be taken into account.
2353                         */
2354                         if(real_y > surface_y)
2355                                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
2356
2357                         /*
2358                                 Calculate material
2359                         */
2360
2361                         // If node is over heightmap y, it's air or water
2362                         if(real_y > surface_y)
2363                         {
2364                                 // If under water level, it's water
2365                                 if(real_y < WATER_LEVEL)
2366                                 {
2367                                         n.d = water_material;
2368                                         n.setLight(LIGHTBANK_DAY,
2369                                                         diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
2370                                         /*
2371                                                 Add to transforming liquid queue (in case it'd
2372                                                 start flowing)
2373                                         */
2374                                         v3s16 real_pos = v3s16(x0,y0,z0) + p*MAP_BLOCKSIZE;
2375                                         m_transforming_liquid.push_back(real_pos);
2376                                 }
2377                                 // else air
2378                                 else
2379                                         n.d = CONTENT_AIR;
2380                         }
2381                         // Else it's ground or dungeons (air)
2382                         else
2383                         {
2384                                 // If it's surface_depth under ground, it's stone
2385                                 if(real_y <= surface_y - surface_depth)
2386                                 {
2387                                         n.d = CONTENT_STONE;
2388                                 }
2389                                 else
2390                                 {
2391                                         // It is mud if it is under the first ground
2392                                         // level or under water
2393                                         if(real_y < WATER_LEVEL || real_y <= surface_y - 1)
2394                                         {
2395                                                 n.d = CONTENT_MUD;
2396                                         }
2397                                         else
2398                                         {
2399                                                 n.d = CONTENT_GRASS;
2400                                         }
2401
2402                                         //n.d = CONTENT_MUD;
2403                                         
2404                                         /*// If under water level, it's mud
2405                                         if(real_y < WATER_LEVEL)
2406                                                 n.d = CONTENT_MUD;
2407                                         // Only the topmost node is grass
2408                                         else if(real_y <= surface_y - 1)
2409                                                 n.d = CONTENT_MUD;
2410                                         else
2411                                                 n.d = CONTENT_GRASS;*/
2412                                 }
2413                         }
2414
2415                         block->setNode(v3s16(x0,y0,z0), n);
2416                 }
2417         }
2418         
2419         /*
2420                 Calculate some helper variables
2421         */
2422         
2423         // Completely underground if the highest part of block is under lowest
2424         // ground height.
2425         // This has to be very sure; it's probably one too strict now but
2426         // that's just better.
2427         bool completely_underground =
2428                         block_y * MAP_BLOCKSIZE + MAP_BLOCKSIZE < lowest_ground_y;
2429
2430         bool some_part_underground = block_y * MAP_BLOCKSIZE <= highest_ground_y;
2431
2432         bool mostly_underwater_surface = false;
2433         if(highest_ground_y < WATER_LEVEL
2434                         && some_part_underground && !completely_underground)
2435                 mostly_underwater_surface = true;
2436
2437         /*
2438                 Get local attributes
2439         */
2440
2441         //dstream<<"emergeBlock(): Getting local attributes"<<std::endl;
2442
2443         float caves_amount = 0;
2444         
2445         {
2446                 /*
2447                         NOTE: BEWARE: Too big amount of attribute points slows verything
2448                         down by a lot.
2449                         1 interpolation from 5000 points takes 2-3ms.
2450                 */
2451                 //TimeTaker timer("emergeBlock() local attribute retrieval");
2452                 v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2453                 PointAttributeList *list_caves_amount = m_padb.getList("caves_amount");
2454                 caves_amount = list_caves_amount->getInterpolatedFloat(nodepos2d);
2455         }
2456
2457         //dstream<<"emergeBlock(): Done"<<std::endl;
2458
2459         /*
2460                 Generate dungeons
2461         */
2462
2463         // Initialize temporary table
2464         const s32 ued = MAP_BLOCKSIZE;
2465         bool underground_emptiness[ued*ued*ued];
2466         for(s32 i=0; i<ued*ued*ued; i++)
2467         {
2468                 underground_emptiness[i] = 0;
2469         }
2470         
2471         // Fill table
2472 #if 1
2473         {
2474                 /*
2475                         Initialize orp and ors. Try to find if some neighboring
2476                         MapBlock has a tunnel ended in its side
2477                 */
2478
2479                 v3f orp(
2480                         (float)(myrand()%ued)+0.5,
2481                         (float)(myrand()%ued)+0.5,
2482                         (float)(myrand()%ued)+0.5
2483                 );
2484                 
2485                 bool found_existing = false;
2486
2487                 // Check z-
2488                 try
2489                 {
2490                         s16 z = -1;
2491                         for(s16 y=0; y<ued; y++)
2492                         for(s16 x=0; x<ued; x++)
2493                         {
2494                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2495                                 if(getNode(ap).d == CONTENT_AIR)
2496                                 {
2497                                         orp = v3f(x+1,y+1,0);
2498                                         found_existing = true;
2499                                         goto continue_generating;
2500                                 }
2501                         }
2502                 }
2503                 catch(InvalidPositionException &e){}
2504                 
2505                 // Check z+
2506                 try
2507                 {
2508                         s16 z = ued;
2509                         for(s16 y=0; y<ued; y++)
2510                         for(s16 x=0; x<ued; x++)
2511                         {
2512                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2513                                 if(getNode(ap).d == CONTENT_AIR)
2514                                 {
2515                                         orp = v3f(x+1,y+1,ued-1);
2516                                         found_existing = true;
2517                                         goto continue_generating;
2518                                 }
2519                         }
2520                 }
2521                 catch(InvalidPositionException &e){}
2522                 
2523                 // Check x-
2524                 try
2525                 {
2526                         s16 x = -1;
2527                         for(s16 y=0; y<ued; y++)
2528                         for(s16 z=0; z<ued; z++)
2529                         {
2530                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2531                                 if(getNode(ap).d == CONTENT_AIR)
2532                                 {
2533                                         orp = v3f(0,y+1,z+1);
2534                                         found_existing = true;
2535                                         goto continue_generating;
2536                                 }
2537                         }
2538                 }
2539                 catch(InvalidPositionException &e){}
2540                 
2541                 // Check x+
2542                 try
2543                 {
2544                         s16 x = ued;
2545                         for(s16 y=0; y<ued; y++)
2546                         for(s16 z=0; z<ued; z++)
2547                         {
2548                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2549                                 if(getNode(ap).d == CONTENT_AIR)
2550                                 {
2551                                         orp = v3f(ued-1,y+1,z+1);
2552                                         found_existing = true;
2553                                         goto continue_generating;
2554                                 }
2555                         }
2556                 }
2557                 catch(InvalidPositionException &e){}
2558
2559                 // Check y-
2560                 try
2561                 {
2562                         s16 y = -1;
2563                         for(s16 x=0; x<ued; x++)
2564                         for(s16 z=0; z<ued; z++)
2565                         {
2566                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2567                                 if(getNode(ap).d == CONTENT_AIR)
2568                                 {
2569                                         orp = v3f(x+1,0,z+1);
2570                                         found_existing = true;
2571                                         goto continue_generating;
2572                                 }
2573                         }
2574                 }
2575                 catch(InvalidPositionException &e){}
2576                 
2577                 // Check y+
2578                 try
2579                 {
2580                         s16 y = ued;
2581                         for(s16 x=0; x<ued; x++)
2582                         for(s16 z=0; z<ued; z++)
2583                         {
2584                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
2585                                 if(getNode(ap).d == CONTENT_AIR)
2586                                 {
2587                                         orp = v3f(x+1,ued-1,z+1);
2588                                         found_existing = true;
2589                                         goto continue_generating;
2590                                 }
2591                         }
2592                 }
2593                 catch(InvalidPositionException &e){}
2594
2595 continue_generating:
2596                 
2597                 /*
2598                         Choose whether to actually generate dungeon
2599                 */
2600                 bool do_generate_dungeons = true;
2601                 // Don't generate if no part is underground
2602                 if(!some_part_underground)
2603                 {
2604                         do_generate_dungeons = false;
2605                 }
2606                 // Don't generate if mostly underwater surface
2607                 else if(mostly_underwater_surface)
2608                 {
2609                         do_generate_dungeons = false;
2610                 }
2611                 // Partly underground = cave
2612                 else if(!completely_underground)
2613                 {
2614                         do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
2615                 }
2616                 // Found existing dungeon underground
2617                 else if(found_existing && completely_underground)
2618                 {
2619                         do_generate_dungeons = (rand() % 100 <= (s32)(caves_amount*100));
2620                 }
2621                 // Underground and no dungeons found
2622                 else
2623                 {
2624                         do_generate_dungeons = (rand() % 300 <= (s32)(caves_amount*100));
2625                 }
2626
2627                 if(do_generate_dungeons)
2628                 {
2629                         /*
2630                                 Generate some tunnel starting from orp and ors
2631                         */
2632                         for(u16 i=0; i<3; i++)
2633                         {
2634                                 v3f rp(
2635                                         (float)(myrand()%ued)+0.5,
2636                                         (float)(myrand()%ued)+0.5,
2637                                         (float)(myrand()%ued)+0.5
2638                                 );
2639                                 s16 min_d = 0;
2640                                 s16 max_d = 4;
2641                                 s16 rs = (myrand()%(max_d-min_d+1))+min_d;
2642                                 
2643                                 v3f vec = rp - orp;
2644
2645                                 for(float f=0; f<1.0; f+=0.04)
2646                                 {
2647                                         v3f fp = orp + vec * f;
2648                                         v3s16 cp(fp.X, fp.Y, fp.Z);
2649                                         s16 d0 = -rs/2;
2650                                         s16 d1 = d0 + rs - 1;
2651                                         for(s16 z0=d0; z0<=d1; z0++)
2652                                         {
2653                                                 s16 si = rs - abs(z0);
2654                                                 for(s16 x0=-si; x0<=si-1; x0++)
2655                                                 {
2656                                                         s16 si2 = rs - abs(x0);
2657                                                         for(s16 y0=-si2+1; y0<=si2-1; y0++)
2658                                                         {
2659                                                                 s16 z = cp.Z + z0;
2660                                                                 s16 y = cp.Y + y0;
2661                                                                 s16 x = cp.X + x0;
2662                                                                 v3s16 p(x,y,z);
2663                                                                 if(isInArea(p, ued) == false)
2664                                                                         continue;
2665                                                                 underground_emptiness[ued*ued*z + ued*y + x] = 1;
2666                                                         }
2667                                                 }
2668                                         }
2669                                 }
2670
2671                                 orp = rp;
2672                         }
2673                 }
2674         }
2675 #endif
2676
2677         // Set to true if has caves.
2678         // Set when some non-air is changed to air when making caves.
2679         bool has_dungeons = false;
2680
2681         /*
2682                 Apply temporary cave data to block
2683         */
2684
2685         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2686         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2687         {
2688                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2689                 {
2690                         MapNode n = block->getNode(v3s16(x0,y0,z0));
2691
2692                         // Create dungeons
2693                         if(underground_emptiness[
2694                                         ued*ued*(z0*ued/MAP_BLOCKSIZE)
2695                                         +ued*(y0*ued/MAP_BLOCKSIZE)
2696                                         +(x0*ued/MAP_BLOCKSIZE)])
2697                         {
2698                                 if(is_ground_content(n.d))
2699                                 {
2700                                         // Has now caves
2701                                         has_dungeons = true;
2702                                         // Set air to node
2703                                         n.d = CONTENT_AIR;
2704                                 }
2705                         }
2706
2707                         block->setNode(v3s16(x0,y0,z0), n);
2708                 }
2709         }
2710         
2711         /*
2712                 This is used for guessing whether or not the block should
2713                 receive sunlight from the top if the top block doesn't exist
2714         */
2715         block->setIsUnderground(completely_underground);
2716
2717         /*
2718                 Force lighting update if some part of block is partly
2719                 underground and has caves.
2720         */
2721         /*if(some_part_underground && !completely_underground && has_dungeons)
2722         {
2723                 //dstream<<"Half-ground caves"<<std::endl;
2724                 lighting_invalidated_blocks[block->getPos()] = block;
2725         }*/
2726         
2727         // DEBUG: Always update lighting
2728         //lighting_invalidated_blocks[block->getPos()] = block;
2729
2730         /*
2731                 Add some minerals
2732         */
2733
2734         if(some_part_underground)
2735         {
2736                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
2737
2738                 /*
2739                         Add meseblocks
2740                 */
2741                 for(s16 i=0; i<underground_level/4 + 1; i++)
2742                 {
2743                         if(myrand()%50 == 0)
2744                         {
2745                                 v3s16 cp(
2746                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2747                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2748                                         (myrand()%(MAP_BLOCKSIZE-2))+1
2749                                 );
2750
2751                                 MapNode n;
2752                                 n.d = CONTENT_MESE;
2753                                 
2754                                 //if(is_ground_content(block->getNode(cp).d))
2755                                 if(block->getNode(cp).d == CONTENT_STONE)
2756                                         if(myrand()%8 == 0)
2757                                                 block->setNode(cp, n);
2758
2759                                 for(u16 i=0; i<26; i++)
2760                                 {
2761                                         //if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
2762                                         if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
2763                                                 if(myrand()%8 == 0)
2764                                                         block->setNode(cp+g_26dirs[i], n);
2765                                 }
2766                         }
2767                 }
2768
2769                 /*
2770                         Add coal
2771                 */
2772                 u16 coal_amount = 30.0 * g_settings.getFloat("coal_amount");
2773                 u16 coal_rareness = 60 / coal_amount;
2774                 if(coal_rareness == 0)
2775                         coal_rareness = 1;
2776                 if(myrand()%coal_rareness == 0)
2777                 {
2778                         u16 a = myrand() % 16;
2779                         u16 amount = coal_amount * a*a*a / 1000;
2780                         for(s16 i=0; i<amount; i++)
2781                         {
2782                                 v3s16 cp(
2783                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2784                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2785                                         (myrand()%(MAP_BLOCKSIZE-2))+1
2786                                 );
2787
2788                                 MapNode n;
2789                                 n.d = CONTENT_COALSTONE;
2790
2791                                 //dstream<<"Adding coalstone"<<std::endl;
2792                                 
2793                                 //if(is_ground_content(block->getNode(cp).d))
2794                                 if(block->getNode(cp).d == CONTENT_STONE)
2795                                         if(myrand()%8 == 0)
2796                                                 block->setNode(cp, n);
2797
2798                                 for(u16 i=0; i<26; i++)
2799                                 {
2800                                         //if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
2801                                         if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
2802                                                 if(myrand()%8 == 0)
2803                                                         block->setNode(cp+g_26dirs[i], n);
2804                                 }
2805                         }
2806                 }
2807         }
2808         
2809         /*
2810                 Create a few rats in empty blocks underground
2811         */
2812         if(completely_underground)
2813         {
2814                 //for(u16 i=0; i<2; i++)
2815                 {
2816                         v3s16 cp(
2817                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
2818                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
2819                                 (myrand()%(MAP_BLOCKSIZE-2))+1
2820                         );
2821
2822                         // Check that the place is empty
2823                         //if(!is_ground_content(block->getNode(cp).d))
2824                         if(1)
2825                         {
2826                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
2827                                 block->addObject(obj);
2828                         }
2829                 }
2830         }
2831         
2832         /*
2833                 Add block to sector.
2834         */
2835         sector->insertBlock(block);
2836         
2837         /*
2838                 Sector object stuff
2839         */
2840                 
2841         // An y-wise container of changed blocks
2842         core::map<s16, MapBlock*> changed_blocks_sector;
2843
2844         /*
2845                 Check if any sector's objects can be placed now.
2846                 If so, place them.
2847         */
2848         core::map<v3s16, u8> *objects = sector->getObjects();
2849         core::list<v3s16> objects_to_remove;
2850         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
2851                         i.atEnd() == false; i++)
2852         {
2853                 v3s16 p = i.getNode()->getKey();
2854                 v2s16 p2d(p.X,p.Z);
2855                 u8 d = i.getNode()->getValue();
2856
2857                 // Ground level point (user for stuff that is on ground)
2858                 v3s16 gp = p;
2859                 bool ground_found = true;
2860                 
2861                 // Search real ground level
2862                 try{
2863                         for(;;)
2864                         {
2865                                 MapNode n = sector->getNode(gp);
2866
2867                                 // If not air, go one up and continue to placing the tree
2868                                 if(n.d != CONTENT_AIR)
2869                                 {
2870                                         gp += v3s16(0,1,0);
2871                                         break;
2872                                 }
2873
2874                                 // If air, go one down
2875                                 gp += v3s16(0,-1,0);
2876                         }
2877                 }catch(InvalidPositionException &e)
2878                 {
2879                         // Ground not found.
2880                         ground_found = false;
2881                         // This is most close to ground
2882                         gp += v3s16(0,1,0);
2883                 }
2884
2885                 try
2886                 {
2887
2888                 if(d == SECTOR_OBJECT_TEST)
2889                 {
2890                         if(sector->isValidArea(p + v3s16(0,0,0),
2891                                         p + v3s16(0,0,0), &changed_blocks_sector))
2892                         {
2893                                 MapNode n;
2894                                 n.d = CONTENT_TORCH;
2895                                 sector->setNode(p, n);
2896                                 objects_to_remove.push_back(p);
2897                         }
2898                 }
2899                 else if(d == SECTOR_OBJECT_TREE_1)
2900                 {
2901                         if(ground_found == false)
2902                                 continue;
2903
2904                         v3s16 p_min = gp + v3s16(-1,0,-1);
2905                         v3s16 p_max = gp + v3s16(1,5,1);
2906                         if(sector->isValidArea(p_min, p_max,
2907                                         &changed_blocks_sector))
2908                         {
2909                                 MapNode n;
2910                                 n.d = CONTENT_TREE;
2911                                 sector->setNode(gp+v3s16(0,0,0), n);
2912                                 sector->setNode(gp+v3s16(0,1,0), n);
2913                                 sector->setNode(gp+v3s16(0,2,0), n);
2914                                 sector->setNode(gp+v3s16(0,3,0), n);
2915
2916                                 n.d = CONTENT_LEAVES;
2917
2918                                 if(myrand()%4!=0) sector->setNode(gp+v3s16(0,5,0), n);
2919
2920                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,0), n);
2921                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,0), n);
2922                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,5,-1), n);
2923                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,5,1), n);
2924                                 /*if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,1), n);
2925                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,1), n);
2926                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,5,-1), n);
2927                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,5,-1), n);*/
2928
2929                                 sector->setNode(gp+v3s16(0,4,0), n);
2930                                 
2931                                 sector->setNode(gp+v3s16(-1,4,0), n);
2932                                 sector->setNode(gp+v3s16(1,4,0), n);
2933                                 sector->setNode(gp+v3s16(0,4,-1), n);
2934                                 sector->setNode(gp+v3s16(0,4,1), n);
2935                                 sector->setNode(gp+v3s16(1,4,1), n);
2936                                 sector->setNode(gp+v3s16(-1,4,1), n);
2937                                 sector->setNode(gp+v3s16(-1,4,-1), n);
2938                                 sector->setNode(gp+v3s16(1,4,-1), n);
2939
2940                                 sector->setNode(gp+v3s16(-1,3,0), n);
2941                                 sector->setNode(gp+v3s16(1,3,0), n);
2942                                 sector->setNode(gp+v3s16(0,3,-1), n);
2943                                 sector->setNode(gp+v3s16(0,3,1), n);
2944                                 sector->setNode(gp+v3s16(1,3,1), n);
2945                                 sector->setNode(gp+v3s16(-1,3,1), n);
2946                                 sector->setNode(gp+v3s16(-1,3,-1), n);
2947                                 sector->setNode(gp+v3s16(1,3,-1), n);
2948                                 
2949                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,0), n);
2950                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,0), n);
2951                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,2,-1), n);
2952                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(0,2,1), n);
2953                                 /*if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,1), n);
2954                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,1), n);
2955                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(-1,2,-1), n);
2956                                 if(myrand()%3!=0) sector->setNode(gp+v3s16(1,2,-1), n);*/
2957                                 
2958                                 // Objects are identified by wanted position
2959                                 objects_to_remove.push_back(p);
2960                                 
2961                                 // Lighting has to be recalculated for this one.
2962                                 sector->getBlocksInArea(p_min, p_max, 
2963                                                 lighting_invalidated_blocks);
2964                         }
2965                 }
2966                 else if(d == SECTOR_OBJECT_BUSH_1)
2967                 {
2968                         if(ground_found == false)
2969                                 continue;
2970                         
2971                         if(sector->isValidArea(gp + v3s16(0,0,0),
2972                                         gp + v3s16(0,0,0), &changed_blocks_sector))
2973                         {
2974                                 MapNode n;
2975                                 n.d = CONTENT_LEAVES;
2976                                 sector->setNode(gp+v3s16(0,0,0), n);
2977                                 
2978                                 // Objects are identified by wanted position
2979                                 objects_to_remove.push_back(p);
2980                         }
2981                 }
2982                 else if(d == SECTOR_OBJECT_RAVINE)
2983                 {
2984                         s16 maxdepth = -20;
2985                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
2986                         v3s16 p_max = p + v3s16(6,6,6);
2987                         if(sector->isValidArea(p_min, p_max,
2988                                         &changed_blocks_sector))
2989                         {
2990                                 MapNode n;
2991                                 n.d = CONTENT_STONE;
2992                                 MapNode n2;
2993                                 n2.d = CONTENT_AIR;
2994                                 s16 depth = maxdepth + (myrand()%10);
2995                                 s16 z = 0;
2996                                 s16 minz = -6 - (-2);
2997                                 s16 maxz = 6 -1;
2998                                 for(s16 x=-6; x<=6; x++)
2999                                 {
3000                                         z += -1 + (myrand()%3);
3001                                         if(z < minz)
3002                                                 z = minz;
3003                                         if(z > maxz)
3004                                                 z = maxz;
3005                                         for(s16 y=depth+(myrand()%2); y<=6; y++)
3006                                         {
3007                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
3008                                                                 <<std::endl;*/
3009                                                 {
3010                                                         v3s16 p2 = p + v3s16(x,y,z-2);
3011                                                         if(is_ground_content(sector->getNode(p2).d)
3012                                                                         && !is_mineral(sector->getNode(p2).d))
3013                                                                 sector->setNode(p2, n);
3014                                                 }
3015                                                 {
3016                                                         v3s16 p2 = p + v3s16(x,y,z-1);
3017                                                         if(is_ground_content(sector->getNode(p2).d)
3018                                                                         && !is_mineral(sector->getNode(p2).d))
3019                                                                 sector->setNode(p2, n2);
3020                                                 }
3021                                                 {
3022                                                         v3s16 p2 = p + v3s16(x,y,z+0);
3023                                                         if(is_ground_content(sector->getNode(p2).d)
3024                                                                         && !is_mineral(sector->getNode(p2).d))
3025                                                                 sector->setNode(p2, n2);
3026                                                 }
3027                                                 {
3028                                                         v3s16 p2 = p + v3s16(x,y,z+1);
3029                                                         if(is_ground_content(sector->getNode(p2).d)
3030                                                                         && !is_mineral(sector->getNode(p2).d))
3031                                                                 sector->setNode(p2, n);
3032                                                 }
3033
3034                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
3035                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
3036                                         }
3037                                 }
3038                                 
3039                                 objects_to_remove.push_back(p);
3040                                 
3041                                 // Lighting has to be recalculated for this one.
3042                                 sector->getBlocksInArea(p_min, p_max, 
3043                                                 lighting_invalidated_blocks);
3044                         }
3045                 }
3046                 else
3047                 {
3048                         dstream<<"ServerMap::emergeBlock(): "
3049                                         "Invalid heightmap object"
3050                                         <<std::endl;
3051                 }
3052
3053                 }//try
3054                 catch(InvalidPositionException &e)
3055                 {
3056                         dstream<<"WARNING: "<<__FUNCTION_NAME
3057                                         <<": while inserting object "<<(int)d
3058                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
3059                                         <<" InvalidPositionException.what()="
3060                                         <<e.what()<<std::endl;
3061                         // This is not too fatal and seems to happen sometimes.
3062                         assert(0);
3063                 }
3064         }
3065
3066         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
3067                         i != objects_to_remove.end(); i++)
3068         {
3069                 objects->remove(*i);
3070         }
3071
3072         /*
3073                 Initially update sunlight
3074         */
3075         
3076         {
3077                 core::map<v3s16, bool> light_sources;
3078                 bool black_air_left = false;
3079                 bool bottom_invalid =
3080                                 block->propagateSunlight(light_sources, true,
3081                                 &black_air_left, true);
3082
3083                 // If sunlight didn't reach everywhere and part of block is
3084                 // above ground, lighting has to be properly updated
3085                 if(black_air_left && some_part_underground)
3086                 {
3087                         lighting_invalidated_blocks[block->getPos()] = block;
3088                 }
3089
3090                 if(bottom_invalid)
3091                 {
3092                         lighting_invalidated_blocks[block->getPos()] = block;
3093                 }
3094         }
3095
3096         /*
3097                 Translate sector's changed blocks to global changed blocks
3098         */
3099         
3100         for(core::map<s16, MapBlock*>::Iterator
3101                         i = changed_blocks_sector.getIterator();
3102                         i.atEnd() == false; i++)
3103         {
3104                 MapBlock *block = i.getNode()->getValue();
3105
3106                 changed_blocks.insert(block->getPos(), block);
3107         }
3108
3109         /*
3110                 Debug information
3111         */
3112         if(0)
3113         {
3114                 dstream
3115                 <<"lighting_invalidated_blocks.size()"
3116                 <<", has_dungeons"
3117                 <<", completely_ug"
3118                 <<", some_part_ug"
3119                 <<"  "<<lighting_invalidated_blocks.size()
3120                 <<", "<<has_dungeons
3121                 <<", "<<completely_underground
3122                 <<", "<<some_part_underground
3123                 <<std::endl;
3124         }
3125
3126         /*
3127                 Debug mode operation
3128         */
3129         bool haxmode = g_settings.getBool("haxmode");
3130         if(haxmode)
3131         {
3132                 // Don't calculate lighting at all
3133                 //lighting_invalidated_blocks.clear();
3134         }
3135
3136         return block;
3137 }
3138
3139 void ServerMap::createDir(std::string path)
3140 {
3141         if(fs::CreateDir(path) == false)
3142         {
3143                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
3144                                 <<"\""<<path<<"\""<<std::endl;
3145                 throw BaseException("ServerMap failed to create directory");
3146         }
3147 }
3148
3149 std::string ServerMap::getSectorSubDir(v2s16 pos)
3150 {
3151         char cc[9];
3152         snprintf(cc, 9, "%.4x%.4x",
3153                         (unsigned int)pos.X&0xffff,
3154                         (unsigned int)pos.Y&0xffff);
3155
3156         return std::string(cc);
3157 }
3158
3159 std::string ServerMap::getSectorDir(v2s16 pos)
3160 {
3161         return m_savedir + "/sectors/" + getSectorSubDir(pos);
3162 }
3163
3164 v2s16 ServerMap::getSectorPos(std::string dirname)
3165 {
3166         if(dirname.size() != 8)
3167                 throw InvalidFilenameException("Invalid sector directory name");
3168         unsigned int x, y;
3169         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
3170         if(r != 2)
3171                 throw InvalidFilenameException("Invalid sector directory name");
3172         v2s16 pos((s16)x, (s16)y);
3173         return pos;
3174 }
3175
3176 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
3177 {
3178         v2s16 p2d = getSectorPos(sectordir);
3179
3180         if(blockfile.size() != 4){
3181                 throw InvalidFilenameException("Invalid block filename");
3182         }
3183         unsigned int y;
3184         int r = sscanf(blockfile.c_str(), "%4x", &y);
3185         if(r != 1)
3186                 throw InvalidFilenameException("Invalid block filename");
3187         return v3s16(p2d.X, y, p2d.Y);
3188 }
3189
3190 // Debug helpers
3191 #define ENABLE_SECTOR_SAVING 1
3192 #define ENABLE_SECTOR_LOADING 1
3193 #define ENABLE_BLOCK_SAVING 1
3194 #define ENABLE_BLOCK_LOADING 1
3195
3196 void ServerMap::save(bool only_changed)
3197 {
3198         DSTACK(__FUNCTION_NAME);
3199         if(m_map_saving_enabled == false)
3200         {
3201                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
3202                 return;
3203         }
3204         
3205         if(only_changed == false)
3206                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
3207                                 <<std::endl;
3208         
3209         saveMasterHeightmap();
3210         
3211         u32 sector_meta_count = 0;
3212         u32 block_count = 0;
3213         
3214         { //sectorlock
3215         JMutexAutoLock lock(m_sector_mutex);
3216         
3217         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
3218         for(; i.atEnd() == false; i++)
3219         {
3220                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
3221                 assert(sector->getId() == MAPSECTOR_SERVER);
3222                 
3223                 if(ENABLE_SECTOR_SAVING)
3224                 {
3225                         if(sector->differs_from_disk || only_changed == false)
3226                         {
3227                                 saveSectorMeta(sector);
3228                                 sector_meta_count++;
3229                         }
3230                 }
3231                 if(ENABLE_BLOCK_SAVING)
3232                 {
3233                         core::list<MapBlock*> blocks;
3234                         sector->getBlocks(blocks);
3235                         core::list<MapBlock*>::Iterator j;
3236                         for(j=blocks.begin(); j!=blocks.end(); j++)
3237                         {
3238                                 MapBlock *block = *j;
3239                                 if(block->getChangedFlag() || only_changed == false)
3240                                 {
3241                                         saveBlock(block);
3242                                         block_count++;
3243                                 }
3244                         }
3245                 }
3246         }
3247
3248         }//sectorlock
3249         
3250         /*
3251                 Only print if something happened or saved whole map
3252         */
3253         if(only_changed == false || sector_meta_count != 0
3254                         || block_count != 0)
3255         {
3256                 dstream<<DTIME<<"ServerMap: Written: "
3257                                 <<sector_meta_count<<" sector metadata files, "
3258                                 <<block_count<<" block files"
3259                                 <<std::endl;
3260         }
3261 }
3262
3263 void ServerMap::loadAll()
3264 {
3265         DSTACK(__FUNCTION_NAME);
3266         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
3267
3268         loadMasterHeightmap();
3269
3270         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
3271
3272         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
3273         
3274         JMutexAutoLock lock(m_sector_mutex);
3275         
3276         s32 counter = 0;
3277         s32 printed_counter = -100000;
3278         s32 count = list.size();
3279
3280         std::vector<fs::DirListNode>::iterator i;
3281         for(i=list.begin(); i!=list.end(); i++)
3282         {
3283                 if(counter > printed_counter + 10)
3284                 {
3285                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
3286                         printed_counter = counter;
3287                 }
3288                 counter++;
3289
3290                 MapSector *sector = NULL;
3291
3292                 // We want directories
3293                 if(i->dir == false)
3294                         continue;
3295                 try{
3296                         sector = loadSectorMeta(i->name);
3297                 }
3298                 catch(InvalidFilenameException &e)
3299                 {
3300                         // This catches unknown crap in directory
3301                 }
3302                 
3303                 if(ENABLE_BLOCK_LOADING)
3304                 {
3305                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3306                                         (m_savedir+"/sectors/"+i->name);
3307                         std::vector<fs::DirListNode>::iterator i2;
3308                         for(i2=list2.begin(); i2!=list2.end(); i2++)
3309                         {
3310                                 // We want files
3311                                 if(i2->dir)
3312                                         continue;
3313                                 try{
3314                                         loadBlock(i->name, i2->name, sector);
3315                                 }
3316                                 catch(InvalidFilenameException &e)
3317                                 {
3318                                         // This catches unknown crap in directory
3319                                 }
3320                         }
3321                 }
3322         }
3323         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
3324 }
3325
3326 void ServerMap::saveMasterHeightmap()
3327 {
3328         DSTACK(__FUNCTION_NAME);
3329         createDir(m_savedir);
3330         
3331         std::string fullpath = m_savedir + "/master_heightmap";
3332         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3333         if(o.good() == false)
3334                 throw FileNotGoodException("Cannot open master heightmap");
3335         
3336         // Format used for writing
3337         u8 version = SER_FMT_VER_HIGHEST;
3338
3339 #if 0
3340         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
3341         /*
3342                 [0] u8 serialization version
3343                 [1] X master heightmap
3344         */
3345         u32 fullsize = 1 + hmdata.getSize();
3346         SharedBuffer<u8> data(fullsize);
3347
3348         data[0] = version;
3349         memcpy(&data[1], *hmdata, hmdata.getSize());
3350
3351         o.write((const char*)*data, fullsize);
3352 #endif
3353         
3354         m_heightmap->serialize(o, version);
3355 }
3356
3357 void ServerMap::loadMasterHeightmap()
3358 {
3359         DSTACK(__FUNCTION_NAME);
3360         std::string fullpath = m_savedir + "/master_heightmap";
3361         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3362         if(is.good() == false)
3363                 throw FileNotGoodException("Cannot open master heightmap");
3364         
3365         if(m_heightmap != NULL)
3366                 delete m_heightmap;
3367                 
3368         m_heightmap = UnlimitedHeightmap::deSerialize(is, &m_padb);
3369 }
3370
3371 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3372 {
3373         DSTACK(__FUNCTION_NAME);
3374         // Format used for writing
3375         u8 version = SER_FMT_VER_HIGHEST;
3376         // Get destination
3377         v2s16 pos = sector->getPos();
3378         createDir(m_savedir);
3379         createDir(m_savedir+"/sectors");
3380         std::string dir = getSectorDir(pos);
3381         createDir(dir);
3382         
3383         std::string fullpath = dir + "/heightmap";
3384         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3385         if(o.good() == false)
3386                 throw FileNotGoodException("Cannot open master heightmap");
3387
3388         sector->serialize(o, version);
3389         
3390         sector->differs_from_disk = false;
3391 }
3392
3393 MapSector* ServerMap::loadSectorMeta(std::string dirname)
3394 {
3395         DSTACK(__FUNCTION_NAME);
3396         // Get destination
3397         v2s16 p2d = getSectorPos(dirname);
3398         std::string dir = m_savedir + "/sectors/" + dirname;
3399         
3400         std::string fullpath = dir + "/heightmap";
3401         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3402         if(is.good() == false)
3403                 throw FileNotGoodException("Cannot open sector heightmap");
3404
3405         ServerMapSector *sector = ServerMapSector::deSerialize
3406                         (is, this, p2d, &m_hwrapper, m_sectors);
3407         
3408         sector->differs_from_disk = false;
3409
3410         return sector;
3411 }
3412
3413 bool ServerMap::loadSectorFull(v2s16 p2d)
3414 {
3415         DSTACK(__FUNCTION_NAME);
3416         std::string sectorsubdir = getSectorSubDir(p2d);
3417
3418         MapSector *sector = NULL;
3419
3420         JMutexAutoLock lock(m_sector_mutex);
3421
3422         try{
3423                 sector = loadSectorMeta(sectorsubdir);
3424         }
3425         catch(InvalidFilenameException &e)
3426         {
3427                 return false;
3428         }
3429         catch(FileNotGoodException &e)
3430         {
3431                 return false;
3432         }
3433         catch(std::exception &e)
3434         {
3435                 return false;
3436         }
3437
3438         if(ENABLE_BLOCK_LOADING)
3439         {
3440                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
3441                                 (m_savedir+"/sectors/"+sectorsubdir);
3442                 std::vector<fs::DirListNode>::iterator i2;
3443                 for(i2=list2.begin(); i2!=list2.end(); i2++)
3444                 {
3445                         // We want files
3446                         if(i2->dir)
3447                                 continue;
3448                         try{
3449                                 loadBlock(sectorsubdir, i2->name, sector);
3450                         }
3451                         catch(InvalidFilenameException &e)
3452                         {
3453                                 // This catches unknown crap in directory
3454                         }
3455                 }
3456         }
3457         return true;
3458 }
3459
3460 #if 0
3461 bool ServerMap::deFlushSector(v2s16 p2d)
3462 {
3463         DSTACK(__FUNCTION_NAME);
3464         // See if it already exists in memory
3465         try{
3466                 MapSector *sector = getSectorNoGenerate(p2d);
3467                 return true;
3468         }
3469         catch(InvalidPositionException &e)
3470         {
3471                 /*
3472                         Try to load the sector from disk.
3473                 */
3474                 if(loadSectorFull(p2d) == true)
3475                 {
3476                         return true;
3477                 }
3478         }
3479         return false;
3480 }
3481 #endif
3482
3483 void ServerMap::saveBlock(MapBlock *block)
3484 {
3485         DSTACK(__FUNCTION_NAME);
3486         /*
3487                 Dummy blocks are not written
3488         */
3489         if(block->isDummy())
3490         {
3491                 /*v3s16 p = block->getPos();
3492                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3493                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3494                 return;
3495         }
3496
3497         // Format used for writing
3498         u8 version = SER_FMT_VER_HIGHEST;
3499         // Get destination
3500         v3s16 p3d = block->getPos();
3501         v2s16 p2d(p3d.X, p3d.Z);
3502         createDir(m_savedir);
3503         createDir(m_savedir+"/sectors");
3504         std::string dir = getSectorDir(p2d);
3505         createDir(dir);
3506         
3507         // Block file is map/sectors/xxxxxxxx/xxxx
3508         char cc[5];
3509         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
3510         std::string fullpath = dir + "/" + cc;
3511         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3512         if(o.good() == false)
3513                 throw FileNotGoodException("Cannot open block data");
3514
3515         /*
3516                 [0] u8 serialization version
3517                 [1] data
3518         */
3519         o.write((char*)&version, 1);
3520         
3521         block->serialize(o, version);
3522
3523         /*
3524                 Versions up from 9 have block objects.
3525         */
3526         if(version >= 9)
3527         {
3528                 block->serializeObjects(o, version);
3529         }
3530         
3531         // We just wrote it to the disk
3532         block->resetChangedFlag();
3533 }
3534
3535 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
3536 {
3537         DSTACK(__FUNCTION_NAME);
3538
3539         try{
3540
3541         // Block file is map/sectors/xxxxxxxx/xxxx
3542         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
3543         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3544         if(is.good() == false)
3545                 throw FileNotGoodException("Cannot open block file");
3546
3547         v3s16 p3d = getBlockPos(sectordir, blockfile);
3548         v2s16 p2d(p3d.X, p3d.Z);
3549         
3550         assert(sector->getPos() == p2d);
3551         
3552         u8 version = SER_FMT_VER_INVALID;
3553         is.read((char*)&version, 1);
3554
3555         /*u32 block_size = MapBlock::serializedLength(version);
3556         SharedBuffer<u8> data(block_size);
3557         is.read((char*)*data, block_size);*/
3558
3559         // This will always return a sector because we're the server
3560         //MapSector *sector = emergeSector(p2d);
3561
3562         MapBlock *block = NULL;
3563         bool created_new = false;
3564         try{
3565                 block = sector->getBlockNoCreate(p3d.Y);
3566         }
3567         catch(InvalidPositionException &e)
3568         {
3569                 block = sector->createBlankBlockNoInsert(p3d.Y);
3570                 created_new = true;
3571         }
3572         
3573         // deserialize block data
3574         block->deSerialize(is, version);
3575         
3576         /*
3577                 Versions up from 9 have block objects.
3578         */
3579         if(version >= 9)
3580         {
3581                 block->updateObjects(is, version, NULL, 0);
3582         }
3583
3584         if(created_new)
3585                 sector->insertBlock(block);
3586         
3587         /*
3588                 Convert old formats to new and save
3589         */
3590
3591         // Save old format blocks in new format
3592         if(version < SER_FMT_VER_HIGHEST)
3593         {
3594                 saveBlock(block);
3595         }
3596         
3597         // We just loaded it from the disk, so it's up-to-date.
3598         block->resetChangedFlag();
3599
3600         }
3601         catch(SerializationError &e)
3602         {
3603                 dstream<<"WARNING: Invalid block data on disk "
3604                                 "(SerializationError). Ignoring."
3605                                 <<std::endl;
3606         }
3607 }
3608
3609 // Gets from master heightmap
3610 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
3611 {
3612         assert(m_heightmap != NULL);
3613         /*
3614                 Corner definition:
3615                 v2s16(0,0),
3616                 v2s16(1,0),
3617                 v2s16(1,1),
3618                 v2s16(0,1),
3619         */
3620         corners[0] = m_heightmap->getGroundHeight
3621                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
3622         corners[1] = m_heightmap->getGroundHeight
3623                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
3624         corners[2] = m_heightmap->getGroundHeight
3625                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
3626         corners[3] = m_heightmap->getGroundHeight
3627                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
3628 }
3629
3630 void ServerMap::PrintInfo(std::ostream &out)
3631 {
3632         out<<"ServerMap: ";
3633 }
3634
3635 #ifndef SERVER
3636
3637 /*
3638         ClientMap
3639 */
3640
3641 ClientMap::ClientMap(
3642                 Client *client,
3643                 MapDrawControl &control,
3644                 scene::ISceneNode* parent,
3645                 scene::ISceneManager* mgr,
3646                 s32 id
3647 ):
3648         Map(dout_client),
3649         scene::ISceneNode(parent, mgr, id),
3650         m_client(client),
3651         mesh(NULL),
3652         m_control(control)
3653 {
3654         mesh_mutex.Init();
3655
3656         /*m_box = core::aabbox3d<f32>(0,0,0,
3657                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
3658         /*m_box = core::aabbox3d<f32>(0,0,0,
3659                         map->getSizeNodes().X * BS,
3660                         map->getSizeNodes().Y * BS,
3661                         map->getSizeNodes().Z * BS);*/
3662         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3663                         BS*1000000,BS*1000000,BS*1000000);
3664         
3665         //setPosition(v3f(BS,BS,BS));
3666 }
3667
3668 ClientMap::~ClientMap()
3669 {
3670         JMutexAutoLock lock(mesh_mutex);
3671         
3672         if(mesh != NULL)
3673         {
3674                 mesh->drop();
3675                 mesh = NULL;
3676         }
3677 }
3678
3679 MapSector * ClientMap::emergeSector(v2s16 p2d)
3680 {
3681         DSTACK(__FUNCTION_NAME);
3682         // Check that it doesn't exist already
3683         try{
3684                 return getSectorNoGenerate(p2d);
3685         }
3686         catch(InvalidPositionException &e)
3687         {
3688         }
3689         
3690         // Create a sector with no heightmaps
3691         ClientMapSector *sector = new ClientMapSector(this, p2d);
3692         
3693         {
3694                 JMutexAutoLock lock(m_sector_mutex);
3695                 m_sectors.insert(p2d, sector);
3696         }
3697         
3698         return sector;
3699 }
3700
3701 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3702 {
3703         DSTACK(__FUNCTION_NAME);
3704         ClientMapSector *sector = NULL;
3705
3706         JMutexAutoLock lock(m_sector_mutex);
3707         
3708         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3709
3710         if(n != NULL)
3711         {
3712                 sector = (ClientMapSector*)n->getValue();
3713                 assert(sector->getId() == MAPSECTOR_CLIENT);
3714         }
3715         else
3716         {
3717                 sector = new ClientMapSector(this, p2d);
3718                 {
3719                         JMutexAutoLock lock(m_sector_mutex);
3720                         m_sectors.insert(p2d, sector);
3721                 }
3722         }
3723
3724         sector->deSerialize(is);
3725 }
3726
3727 void ClientMap::OnRegisterSceneNode()
3728 {
3729         if(IsVisible)
3730         {
3731                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3732                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3733         }
3734
3735         ISceneNode::OnRegisterSceneNode();
3736 }
3737
3738 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3739 {
3740         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3741         DSTACK(__FUNCTION_NAME);
3742
3743         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3744
3745         /*
3746                 Get time for measuring timeout.
3747                 
3748                 Measuring time is very useful for long delays when the
3749                 machine is swapping a lot.
3750         */
3751         int time1 = time(0);
3752
3753         u32 daynight_ratio = m_client->getDayNightRatio();
3754
3755         m_camera_mutex.Lock();
3756         v3f camera_position = m_camera_position;
3757         v3f camera_direction = m_camera_direction;
3758         m_camera_mutex.Unlock();
3759
3760         /*
3761                 Get all blocks and draw all visible ones
3762         */
3763
3764         v3s16 cam_pos_nodes(
3765                         camera_position.X / BS,
3766                         camera_position.Y / BS,
3767                         camera_position.Z / BS);
3768
3769         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3770
3771         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3772         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3773
3774         // Take a fair amount as we will be dropping more out later
3775         v3s16 p_blocks_min(
3776                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
3777                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
3778                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
3779         v3s16 p_blocks_max(
3780                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3781                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3782                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3783         
3784         u32 vertex_count = 0;
3785         
3786         // For limiting number of mesh updates per frame
3787         u32 mesh_update_count = 0;
3788         
3789         u32 blocks_would_have_drawn = 0;
3790         u32 blocks_drawn = 0;
3791
3792         //NOTE: The sectors map should be locked but we're not doing it
3793         // because it'd cause too much delays
3794
3795         int timecheck_counter = 0;
3796         core::map<v2s16, MapSector*>::Iterator si;
3797         si = m_sectors.getIterator();
3798         for(; si.atEnd() == false; si++)
3799         {
3800                 {
3801                         timecheck_counter++;
3802                         if(timecheck_counter > 50)
3803                         {
3804                                 int time2 = time(0);
3805                                 if(time2 > time1 + 4)
3806                                 {
3807                                         dstream<<"ClientMap::renderMap(): "
3808                                                 "Rendering takes ages, returning."
3809                                                 <<std::endl;
3810                                         return;
3811                                 }
3812                         }
3813                 }
3814
3815                 MapSector *sector = si.getNode()->getValue();
3816                 v2s16 sp = sector->getPos();
3817                 
3818                 if(m_control.range_all == false)
3819                 {
3820                         if(sp.X < p_blocks_min.X
3821                         || sp.X > p_blocks_max.X
3822                         || sp.Y < p_blocks_min.Z
3823                         || sp.Y > p_blocks_max.Z)
3824                                 continue;
3825                 }
3826
3827                 core::list< MapBlock * > sectorblocks;
3828                 sector->getBlocks(sectorblocks);
3829                 
3830                 /*
3831                         Draw blocks
3832                 */
3833
3834                 core::list< MapBlock * >::Iterator i;
3835                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3836                 {
3837                         MapBlock *block = *i;
3838
3839                         /*
3840                                 Compare block position to camera position, skip
3841                                 if not seen on display
3842                         */
3843                         
3844                         float range = 100000 * BS;
3845                         if(m_control.range_all == false)
3846                                 range = m_control.wanted_range * BS;
3847
3848                         if(isBlockInSight(block->getPos(), camera_position,
3849                                         camera_direction, range) == false)
3850                         {
3851                                 continue;
3852                         }
3853
3854 #if 0                   
3855                         v3s16 blockpos_nodes = block->getPosRelative();
3856                         
3857                         // Block center position
3858                         v3f blockpos(
3859                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
3860                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
3861                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
3862                         );
3863
3864                         // Block position relative to camera
3865                         v3f blockpos_relative = blockpos - camera_position;
3866
3867                         // Distance in camera direction (+=front, -=back)
3868                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
3869
3870                         // Total distance
3871                         f32 d = blockpos_relative.getLength();
3872                         
3873                         if(m_control.range_all == false)
3874                         {
3875                                 // If block is far away, don't draw it
3876                                 if(d > m_control.wanted_range * BS)
3877                                         continue;
3878                         }
3879                         
3880                         // Maximum radius of a block
3881                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
3882                         
3883                         // If block is (nearly) touching the camera, don't
3884                         // bother validating further (that is, render it anyway)
3885                         if(d > block_max_radius * 1.5)
3886                         {
3887                                 // Cosine of the angle between the camera direction
3888                                 // and the block direction (camera_direction is an unit vector)
3889                                 f32 cosangle = dforward / d;
3890                                 
3891                                 // Compensate for the size of the block
3892                                 // (as the block has to be shown even if it's a bit off FOV)
3893                                 // This is an estimate.
3894                                 cosangle += block_max_radius / dforward;
3895
3896                                 // If block is not in the field of view, skip it
3897                                 //if(cosangle < cos(FOV_ANGLE/2))
3898                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
3899                                         continue;
3900                         }
3901 #endif                  
3902
3903                         v3s16 blockpos_nodes = block->getPosRelative();
3904                         
3905                         // Block center position
3906                         v3f blockpos(
3907                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
3908                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
3909                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
3910                         );
3911
3912                         // Block position relative to camera
3913                         v3f blockpos_relative = blockpos - camera_position;
3914
3915                         // Total distance
3916                         f32 d = blockpos_relative.getLength();
3917                         
3918 #if 1
3919                         /*
3920                                 Update expired mesh
3921                         */
3922
3923                         bool mesh_expired = false;
3924                         
3925                         {
3926                                 JMutexAutoLock lock(block->mesh_mutex);
3927
3928                                 mesh_expired = block->getMeshExpired();
3929
3930                                 // Mesh has not been expired and there is no mesh:
3931                                 // block has no content
3932                                 if(block->mesh == NULL && mesh_expired == false)
3933                                         continue;
3934                         }
3935
3936                         f32 faraway = BS*50;
3937                         //f32 faraway = m_control.wanted_range * BS;
3938                         
3939                         /*
3940                                 This has to be done with the mesh_mutex unlocked
3941                         */
3942                         // Pretty random but this should work somewhat nicely
3943                         if(mesh_expired && (
3944                                         (mesh_update_count < 3
3945                                                 && (d < faraway || mesh_update_count < 2)
3946                                         )
3947                                         || 
3948                                         (m_control.range_all && mesh_update_count < 20)
3949                                 )
3950                         )
3951                         /*if(mesh_expired && mesh_update_count < 6
3952                                         && (d < faraway || mesh_update_count < 3))*/
3953                         {
3954                                 mesh_update_count++;
3955
3956                                 // Mesh has been expired: generate new mesh
3957                                 //block->updateMeshes(daynight_i);
3958                                 block->updateMesh(daynight_ratio);
3959
3960                                 mesh_expired = false;
3961                         }
3962                         
3963                         /*
3964                                 Don't draw an expired mesh that is far away
3965                         */
3966                         /*if(mesh_expired && d >= faraway)
3967                         //if(mesh_expired)
3968                         {
3969                                 // Instead, delete it
3970                                 JMutexAutoLock lock(block->mesh_mutex);
3971                                 if(block->mesh)
3972                                 {
3973                                         block->mesh->drop();
3974                                         block->mesh = NULL;
3975                                 }
3976                                 // And continue to next block
3977                                 continue;
3978                         }*/
3979 #endif
3980                         /*
3981                                 Draw the faces of the block
3982                         */
3983                         {
3984                                 JMutexAutoLock lock(block->mesh_mutex);
3985
3986                                 scene::SMesh *mesh = block->mesh;
3987
3988                                 if(mesh == NULL)
3989                                         continue;
3990                                 
3991                                 blocks_would_have_drawn++;
3992                                 if(blocks_drawn >= m_control.wanted_max_blocks
3993                                                 && m_control.range_all == false
3994                                                 && d > m_control.wanted_min_range * BS)
3995                                         continue;
3996                                 blocks_drawn++;
3997
3998                                 u32 c = mesh->getMeshBufferCount();
3999
4000                                 for(u32 i=0; i<c; i++)
4001                                 {
4002                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
4003                                         const video::SMaterial& material = buf->getMaterial();
4004                                         video::IMaterialRenderer* rnd =
4005                                                         driver->getMaterialRenderer(material.MaterialType);
4006                                         bool transparent = (rnd && rnd->isTransparent());
4007                                         // Render transparent on transparent pass and likewise.
4008                                         if(transparent == is_transparent_pass)
4009                                         {
4010                                                 driver->setMaterial(buf->getMaterial());
4011                                                 driver->drawMeshBuffer(buf);
4012                                                 vertex_count += buf->getVertexCount();
4013                                         }
4014                                 }
4015                         }
4016                 } // foreach sectorblocks
4017         }
4018         
4019         m_control.blocks_drawn = blocks_drawn;
4020         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
4021
4022         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
4023                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
4024 }
4025
4026 v3s16 ClientMap::setTempMod(v3s16 p, NodeMod mod, bool *changed)
4027 {
4028         /*
4029                 Add it to all blocks touching it
4030         */
4031         v3s16 dirs[7] = {
4032                 v3s16(0,0,0), // this
4033                 v3s16(0,0,1), // back
4034                 v3s16(0,1,0), // top
4035                 v3s16(1,0,0), // right
4036                 v3s16(0,0,-1), // front
4037                 v3s16(0,-1,0), // bottom
4038                 v3s16(-1,0,0), // left
4039         };
4040         for(u16 i=0; i<7; i++)
4041         {
4042                 v3s16 p2 = p + dirs[i];
4043                 // Block position of neighbor (or requested) node
4044                 v3s16 blockpos = getNodeBlockPos(p2);
4045                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4046                 if(blockref == NULL)
4047                         continue;
4048                 // Relative position of requested node
4049                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4050                 if(blockref->setTempMod(relpos, mod))
4051                 {
4052                         if(changed != NULL)
4053                                 *changed = true;
4054                 }
4055         }
4056         return getNodeBlockPos(p);
4057 }
4058 v3s16 ClientMap::clearTempMod(v3s16 p, bool *changed)
4059 {
4060         v3s16 dirs[7] = {
4061                 v3s16(0,0,0), // this
4062                 v3s16(0,0,1), // back
4063                 v3s16(0,1,0), // top
4064                 v3s16(1,0,0), // right
4065                 v3s16(0,0,-1), // front
4066                 v3s16(0,-1,0), // bottom
4067                 v3s16(-1,0,0), // left
4068         };
4069         for(u16 i=0; i<7; i++)
4070         {
4071                 v3s16 p2 = p + dirs[i];
4072                 // Block position of neighbor (or requested) node
4073                 v3s16 blockpos = getNodeBlockPos(p2);
4074                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4075                 if(blockref == NULL)
4076                         continue;
4077                 // Relative position of requested node
4078                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4079                 if(blockref->clearTempMod(relpos))
4080                 {
4081                         if(changed != NULL)
4082                                 *changed = true;
4083                 }
4084         }
4085         return getNodeBlockPos(p);
4086 }
4087
4088 void ClientMap::PrintInfo(std::ostream &out)
4089 {
4090         out<<"ClientMap: ";
4091 }
4092
4093 #endif // !SERVER
4094
4095 /*
4096         MapVoxelManipulator
4097 */
4098
4099 MapVoxelManipulator::MapVoxelManipulator(Map *map)
4100 {
4101         m_map = map;
4102 }
4103
4104 MapVoxelManipulator::~MapVoxelManipulator()
4105 {
4106         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4107                         <<std::endl;*/
4108 }
4109
4110 #if 1
4111 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4112 {
4113         TimeTaker timer1("emerge", &emerge_time);
4114
4115         // Units of these are MapBlocks
4116         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4117         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4118
4119         VoxelArea block_area_nodes
4120                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4121
4122         addArea(block_area_nodes);
4123
4124         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4125         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4126         for(s32 x=p_min.X; x<=p_max.X; x++)
4127         {
4128                 v3s16 p(x,y,z);
4129                 core::map<v3s16, bool>::Node *n;
4130                 n = m_loaded_blocks.find(p);
4131                 if(n != NULL)
4132                         continue;
4133                 
4134                 bool block_data_inexistent = false;
4135                 try
4136                 {
4137                         TimeTaker timer1("emerge load", &emerge_load_time);
4138
4139                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
4140                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4141                                         <<" wanted area: ";
4142                         a.print(dstream);
4143                         dstream<<std::endl;*/
4144                         
4145                         MapBlock *block = m_map->getBlockNoCreate(p);
4146                         if(block->isDummy())
4147                                 block_data_inexistent = true;
4148                         else
4149                                 block->copyTo(*this);
4150                 }
4151                 catch(InvalidPositionException &e)
4152                 {
4153                         block_data_inexistent = true;
4154                 }
4155
4156                 if(block_data_inexistent)
4157                 {
4158                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4159                         // Fill with VOXELFLAG_INEXISTENT
4160                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4161                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4162                         {
4163                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4164                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4165                         }
4166                 }
4167
4168                 m_loaded_blocks.insert(p, true);
4169         }
4170
4171         //dstream<<"emerge done"<<std::endl;
4172 }
4173 #endif
4174
4175 #if 0
4176 /*
4177         NOTE: This is slow
4178 */
4179 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4180 {
4181         TimeTaker timer1("emerge", &emerge_time);
4182         
4183         v3s16 size = a.getExtent();
4184         
4185         VoxelArea padded = a;
4186         padded.pad(m_area.getExtent() / 4);
4187         addArea(padded);
4188
4189         for(s16 z=0; z<size.Z; z++)
4190         for(s16 y=0; y<size.Y; y++)
4191         for(s16 x=0; x<size.X; x++)
4192         {
4193                 v3s16 p(x,y,z);
4194                 s32 i = m_area.index(a.MinEdge + p);
4195                 // Don't touch nodes that have already been loaded
4196                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
4197                         continue;
4198                 try
4199                 {
4200                         TimeTaker timer1("emerge load", &emerge_load_time);
4201                         MapNode n = m_map->getNode(a.MinEdge + p);
4202                         m_data[i] = n;
4203                         m_flags[i] = 0;
4204                 }
4205                 catch(InvalidPositionException &e)
4206                 {
4207                         m_flags[i] = VOXELFLAG_INEXISTENT;
4208                 }
4209         }
4210 }
4211 #endif
4212
4213
4214 /*
4215         TODO: Add an option to only update eg. water and air nodes.
4216               This will make it interfere less with important stuff if
4217                   run on background.
4218 */
4219 void MapVoxelManipulator::blitBack
4220                 (core::map<v3s16, MapBlock*> & modified_blocks)
4221 {
4222         if(m_area.getExtent() == v3s16(0,0,0))
4223                 return;
4224         
4225         //TimeTaker timer1("blitBack");
4226
4227         /*dstream<<"blitBack(): m_loaded_blocks.size()="
4228                         <<m_loaded_blocks.size()<<std::endl;*/
4229         
4230         /*
4231                 Initialize block cache
4232         */
4233         v3s16 blockpos_last;
4234         MapBlock *block = NULL;
4235         bool block_checked_in_modified = false;
4236
4237         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4238         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4239         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4240         {
4241                 v3s16 p(x,y,z);
4242
4243                 u8 f = m_flags[m_area.index(p)];
4244                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4245                         continue;
4246
4247                 MapNode &n = m_data[m_area.index(p)];
4248                         
4249                 v3s16 blockpos = getNodeBlockPos(p);
4250                 
4251                 try
4252                 {
4253                         // Get block
4254                         if(block == NULL || blockpos != blockpos_last){
4255                                 block = m_map->getBlockNoCreate(blockpos);
4256                                 blockpos_last = blockpos;
4257                                 block_checked_in_modified = false;
4258                         }
4259                         
4260                         // Calculate relative position in block
4261                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4262
4263                         // Don't continue if nothing has changed here
4264                         if(block->getNode(relpos) == n)
4265                                 continue;
4266
4267                         //m_map->setNode(m_area.MinEdge + p, n);
4268                         block->setNode(relpos, n);
4269                         
4270                         /*
4271                                 Make sure block is in modified_blocks
4272                         */
4273                         if(block_checked_in_modified == false)
4274                         {
4275                                 modified_blocks[blockpos] = block;
4276                                 block_checked_in_modified = true;
4277                         }
4278                 }
4279                 catch(InvalidPositionException &e)
4280                 {
4281                 }
4282         }
4283 }
4284
4285 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4286                 MapVoxelManipulator(map)
4287 {
4288 }
4289
4290 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4291 {
4292 }
4293
4294 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4295 {
4296         // Just create the area to avoid segfaults
4297         VoxelManipulator::emerge(a, caller_id);
4298
4299         /*
4300                 Just create the area to avoid segfaults
4301         */
4302         /*addArea(a);
4303         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4304         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4305         for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
4306         {
4307                 s32 i = m_area.index(x,y,z);
4308                 // Don't touch nodes that have already been loaded
4309                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
4310                         continue;
4311                 m_flags[i] = VOXELFLAG_INEXISTENT;
4312         }*/
4313 }
4314
4315 void ManualMapVoxelManipulator::initialEmerge(
4316                 v3s16 blockpos_min, v3s16 blockpos_max)
4317 {
4318         TimeTaker timer1("emerge", &emerge_time);
4319
4320         // Units of these are MapBlocks
4321         v3s16 p_min = blockpos_min;
4322         v3s16 p_max = blockpos_max;
4323
4324         VoxelArea block_area_nodes
4325                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4326
4327         addArea(block_area_nodes);
4328
4329         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4330         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4331         for(s32 x=p_min.X; x<=p_max.X; x++)
4332         {
4333                 v3s16 p(x,y,z);
4334                 core::map<v3s16, bool>::Node *n;
4335                 n = m_loaded_blocks.find(p);
4336                 if(n != NULL)
4337                         continue;
4338                 
4339                 bool block_data_inexistent = false;
4340                 try
4341                 {
4342                         TimeTaker timer1("emerge load", &emerge_load_time);
4343
4344                         MapBlock *block = m_map->getBlockNoCreate(p);
4345                         if(block->isDummy())
4346                                 block_data_inexistent = true;
4347                         else
4348                                 block->copyTo(*this);
4349                 }
4350                 catch(InvalidPositionException &e)
4351                 {
4352                         block_data_inexistent = true;
4353                 }
4354
4355                 if(block_data_inexistent)
4356                 {
4357                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4358                         // Fill with VOXELFLAG_INEXISTENT
4359                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4360                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4361                         {
4362                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4363                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4364                         }
4365                 }
4366
4367                 m_loaded_blocks.insert(p, true);
4368         }
4369 }
4370
4371 //END