working good
[oweals/minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "map.h"
21 #include "main.h"
22 #include "jmutexautolock.h"
23 #include "client.h"
24 #include "filesys.h"
25 #include "utility.h"
26 #include "voxel.h"
27 #include "porting.h"
28
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         drawoffset(0,0,0)
40 {
41         m_sector_mutex.Init();
42         m_camera_mutex.Init();
43         assert(m_sector_mutex.IsInitialized());
44         assert(m_camera_mutex.IsInitialized());
45         
46         // Get this so that the player can stay on it at first
47         //getSector(v2s16(0,0));
48 }
49
50 Map::~Map()
51 {
52         /*
53                 Stop updater thread
54         */
55         /*updater.setRun(false);
56         while(updater.IsRunning())
57                 sleep_s(1);*/
58
59         /*
60                 Free all MapSectors.
61         */
62         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
63         for(; i.atEnd() == false; i++)
64         {
65                 MapSector *sector = i.getNode()->getValue();
66                 delete sector;
67         }
68 }
69
70 MapSector * Map::getSectorNoGenerate(v2s16 p)
71 {
72         JMutexAutoLock lock(m_sector_mutex);
73
74         if(m_sector_cache != NULL && p == m_sector_cache_p){
75                 MapSector * sector = m_sector_cache;
76                 // Reset inactivity timer
77                 sector->usage_timer = 0.0;
78                 return sector;
79         }
80         
81         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
82         // If sector doesn't exist, throw an exception
83         if(n == NULL)
84         {
85                 throw InvalidPositionException();
86         }
87         
88         MapSector *sector = n->getValue();
89         
90         // Cache the last result
91         m_sector_cache_p = p;
92         m_sector_cache = sector;
93
94         //MapSector * ref(sector);
95         
96         // Reset inactivity timer
97         sector->usage_timer = 0.0;
98         return sector;
99 }
100
101 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
102 {       
103         v2s16 p2d(p3d.X, p3d.Z);
104         MapSector * sector = getSectorNoGenerate(p2d);
105
106         MapBlock *block = sector->getBlockNoCreate(p3d.Y);
107
108         return block;
109 }
110
111 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
112 {
113         try
114         {
115                 v2s16 p2d(p3d.X, p3d.Z);
116                 MapSector * sector = getSectorNoGenerate(p2d);
117                 MapBlock *block = sector->getBlockNoCreate(p3d.Y);
118                 return block;
119         }
120         catch(InvalidPositionException &e)
121         {
122                 return NULL;
123         }
124 }
125
126 f32 Map::getGroundHeight(v2s16 p, bool generate)
127 {
128         try{
129                 v2s16 sectorpos = getNodeSectorPos(p);
130                 MapSector * sref = getSectorNoGenerate(sectorpos);
131                 v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
132                 f32 y = sref->getGroundHeight(relpos);
133                 return y;
134         }
135         catch(InvalidPositionException &e)
136         {
137                 return GROUNDHEIGHT_NOTFOUND_SETVALUE;
138         }
139 }
140
141 void Map::setGroundHeight(v2s16 p, f32 y, bool generate)
142 {
143         /*m_dout<<DTIME<<"Map::setGroundHeight(("
144                         <<p.X<<","<<p.Y
145                         <<"), "<<y<<")"<<std::endl;*/
146         v2s16 sectorpos = getNodeSectorPos(p);
147         MapSector * sref = getSectorNoGenerate(sectorpos);
148         v2s16 relpos = p - sectorpos * MAP_BLOCKSIZE;
149         //sref->mutex.Lock();
150         sref->setGroundHeight(relpos, y);
151         //sref->mutex.Unlock();
152 }
153
154 bool Map::isNodeUnderground(v3s16 p)
155 {
156         v3s16 blockpos = getNodeBlockPos(p);
157         try{
158                 MapBlock * block = getBlockNoCreate(blockpos);
159                 return block->getIsUnderground();
160         }
161         catch(InvalidPositionException &e)
162         {
163                 return false;
164         }
165 }
166
167 /*
168         Goes recursively through the neighbours of the node.
169
170         Alters only transparent nodes.
171
172         If the lighting of the neighbour is lower than the lighting of
173         the node was (before changing it to 0 at the step before), the
174         lighting of the neighbour is set to 0 and then the same stuff
175         repeats for the neighbour.
176
177         The ending nodes of the routine are stored in light_sources.
178         This is useful when a light is removed. In such case, this
179         routine can be called for the light node and then again for
180         light_sources to re-light the area without the removed light.
181
182         values of from_nodes are lighting values.
183 */
184 void Map::unspreadLight(enum LightBank bank,
185                 core::map<v3s16, u8> & from_nodes,
186                 core::map<v3s16, bool> & light_sources,
187                 core::map<v3s16, MapBlock*>  & modified_blocks)
188 {
189         v3s16 dirs[6] = {
190                 v3s16(0,0,1), // back
191                 v3s16(0,1,0), // top
192                 v3s16(1,0,0), // right
193                 v3s16(0,0,-1), // front
194                 v3s16(0,-1,0), // bottom
195                 v3s16(-1,0,0), // left
196         };
197         
198         if(from_nodes.size() == 0)
199                 return;
200         
201         u32 blockchangecount = 0;
202
203         core::map<v3s16, u8> unlighted_nodes;
204         core::map<v3s16, u8>::Iterator j;
205         j = from_nodes.getIterator();
206
207         /*
208                 Initialize block cache
209         */
210         v3s16 blockpos_last;
211         MapBlock *block = NULL;
212         // Cache this a bit, too
213         bool block_checked_in_modified = false;
214         
215         for(; j.atEnd() == false; j++)
216         {
217                 v3s16 pos = j.getNode()->getKey();
218                 v3s16 blockpos = getNodeBlockPos(pos);
219                 
220                 // Only fetch a new block if the block position has changed
221                 try{
222                         if(block == NULL || blockpos != blockpos_last){
223                                 block = getBlockNoCreate(blockpos);
224                                 blockpos_last = blockpos;
225
226                                 block_checked_in_modified = false;
227                                 blockchangecount++;
228                         }
229                 }
230                 catch(InvalidPositionException &e)
231                 {
232                         continue;
233                 }
234
235                 if(block->isDummy())
236                         continue;
237
238                 // Calculate relative position in block
239                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
240
241                 // Get node straight from the block
242                 MapNode n = block->getNode(relpos);
243                 
244                 u8 oldlight = j.getNode()->getValue();
245                 
246                 // Loop through 6 neighbors
247                 for(u16 i=0; i<6; i++)
248                 {
249                         // Get the position of the neighbor node
250                         v3s16 n2pos = pos + dirs[i];
251                         
252                         // Get the block where the node is located
253                         v3s16 blockpos = getNodeBlockPos(n2pos);
254
255                         try
256                         {
257                                 // Only fetch a new block if the block position has changed
258                                 try{
259                                         if(block == NULL || blockpos != blockpos_last){
260                                                 block = getBlockNoCreate(blockpos);
261                                                 blockpos_last = blockpos;
262
263                                                 block_checked_in_modified = false;
264                                                 blockchangecount++;
265                                         }
266                                 }
267                                 catch(InvalidPositionException &e)
268                                 {
269                                         continue;
270                                 }
271                                 
272                                 // Calculate relative position in block
273                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
274                                 // Get node straight from the block
275                                 MapNode n2 = block->getNode(relpos);
276                                 
277                                 bool changed = false;
278
279                                 //TODO: Optimize output by optimizing light_sources?
280
281                                 /*
282                                         If the neighbor is dimmer than what was specified
283                                         as oldlight (the light of the previous node)
284                                 */
285                                 if(n2.getLight(bank) < oldlight)
286                                 {
287                                         /*
288                                                 And the neighbor is transparent and it has some light
289                                         */
290                                         if(n2.light_propagates() && n2.getLight(bank) != 0)
291                                         {
292                                                 /*
293                                                         Set light to 0 and add to queue
294                                                 */
295
296                                                 u8 current_light = n2.getLight(bank);
297                                                 n2.setLight(bank, 0);
298                                                 block->setNode(relpos, n2);
299
300                                                 unlighted_nodes.insert(n2pos, current_light);
301                                                 changed = true;
302
303                                                 /*
304                                                         Remove from light_sources if it is there
305                                                         NOTE: This doesn't happen nearly at all
306                                                 */
307                                                 /*if(light_sources.find(n2pos))
308                                                 {
309                                                         std::cout<<"Removed from light_sources"<<std::endl;
310                                                         light_sources.remove(n2pos);
311                                                 }*/
312                                         }
313                                         
314                                         /*// DEBUG
315                                         if(light_sources.find(n2pos) != NULL)
316                                                 light_sources.remove(n2pos);*/
317                                 }
318                                 else{
319                                         light_sources.insert(n2pos, true);
320                                 }
321
322                                 // Add to modified_blocks
323                                 if(changed == true && block_checked_in_modified == false)
324                                 {
325                                         // If the block is not found in modified_blocks, add.
326                                         if(modified_blocks.find(blockpos) == NULL)
327                                         {
328                                                 modified_blocks.insert(blockpos, block);
329                                         }
330                                         block_checked_in_modified = true;
331                                 }
332                         }
333                         catch(InvalidPositionException &e)
334                         {
335                                 continue;
336                         }
337                 }
338         }
339
340         /*dstream<<"unspreadLight(): Changed block "
341                         <<blockchangecount<<" times"
342                         <<" for "<<from_nodes.size()<<" nodes"
343                         <<std::endl;*/
344         
345         if(unlighted_nodes.size() > 0)
346                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
347 }
348
349 /*
350         A single-node wrapper of the above
351 */
352 void Map::unLightNeighbors(enum LightBank bank,
353                 v3s16 pos, u8 lightwas,
354                 core::map<v3s16, bool> & light_sources,
355                 core::map<v3s16, MapBlock*>  & modified_blocks)
356 {
357         core::map<v3s16, u8> from_nodes;
358         from_nodes.insert(pos, lightwas);
359
360         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
361 }
362
363 /*
364         Lights neighbors of from_nodes, collects all them and then
365         goes on recursively.
366 */
367 void Map::spreadLight(enum LightBank bank,
368                 core::map<v3s16, bool> & from_nodes,
369                 core::map<v3s16, MapBlock*> & modified_blocks)
370 {
371         const v3s16 dirs[6] = {
372                 v3s16(0,0,1), // back
373                 v3s16(0,1,0), // top
374                 v3s16(1,0,0), // right
375                 v3s16(0,0,-1), // front
376                 v3s16(0,-1,0), // bottom
377                 v3s16(-1,0,0), // left
378         };
379
380         if(from_nodes.size() == 0)
381                 return;
382         
383         u32 blockchangecount = 0;
384
385         core::map<v3s16, bool> lighted_nodes;
386         core::map<v3s16, bool>::Iterator j;
387         j = from_nodes.getIterator();
388
389         /*
390                 Initialize block cache
391         */
392         v3s16 blockpos_last;
393         MapBlock *block = NULL;
394         // Cache this a bit, too
395         bool block_checked_in_modified = false;
396         
397         for(; j.atEnd() == false; j++)
398         //for(; j != from_nodes.end(); j++)
399         {
400                 v3s16 pos = j.getNode()->getKey();
401                 //v3s16 pos = *j;
402                 //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
403                 v3s16 blockpos = getNodeBlockPos(pos);
404                 
405                 // Only fetch a new block if the block position has changed
406                 try{
407                         if(block == NULL || blockpos != blockpos_last){
408                                 block = getBlockNoCreate(blockpos);
409                                 blockpos_last = blockpos;
410
411                                 block_checked_in_modified = false;
412                                 blockchangecount++;
413                         }
414                 }
415                 catch(InvalidPositionException &e)
416                 {
417                         continue;
418                 }
419
420                 if(block->isDummy())
421                         continue;
422
423                 // Calculate relative position in block
424                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
425
426                 // Get node straight from the block
427                 MapNode n = block->getNode(relpos);
428
429                 u8 oldlight = n.getLight(bank);
430                 u8 newlight = diminish_light(oldlight);
431
432                 // Loop through 6 neighbors
433                 for(u16 i=0; i<6; i++){
434                         // Get the position of the neighbor node
435                         v3s16 n2pos = pos + dirs[i];
436                         
437                         // Get the block where the node is located
438                         v3s16 blockpos = getNodeBlockPos(n2pos);
439
440                         try
441                         {
442                                 // Only fetch a new block if the block position has changed
443                                 try{
444                                         if(block == NULL || blockpos != blockpos_last){
445                                                 block = getBlockNoCreate(blockpos);
446                                                 blockpos_last = blockpos;
447
448                                                 block_checked_in_modified = false;
449                                                 blockchangecount++;
450                                         }
451                                 }
452                                 catch(InvalidPositionException &e)
453                                 {
454                                         continue;
455                                 }
456                                 
457                                 // Calculate relative position in block
458                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
459                                 // Get node straight from the block
460                                 MapNode n2 = block->getNode(relpos);
461                                 
462                                 bool changed = false;
463                                 /*
464                                         If the neighbor is brighter than the current node,
465                                         add to list (it will light up this node on its turn)
466                                 */
467                                 if(n2.getLight(bank) > undiminish_light(oldlight))
468                                 {
469                                         lighted_nodes.insert(n2pos, true);
470                                         //lighted_nodes.push_back(n2pos);
471                                         changed = true;
472                                 }
473                                 /*
474                                         If the neighbor is dimmer than how much light this node
475                                         would spread on it, add to list
476                                 */
477                                 if(n2.getLight(bank) < newlight)
478                                 {
479                                         if(n2.light_propagates())
480                                         {
481                                                 n2.setLight(bank, newlight);
482                                                 block->setNode(relpos, n2);
483                                                 lighted_nodes.insert(n2pos, true);
484                                                 //lighted_nodes.push_back(n2pos);
485                                                 changed = true;
486                                         }
487                                 }
488
489                                 // Add to modified_blocks
490                                 if(changed == true && block_checked_in_modified == false)
491                                 {
492                                         // If the block is not found in modified_blocks, add.
493                                         if(modified_blocks.find(blockpos) == NULL)
494                                         {
495                                                 modified_blocks.insert(blockpos, block);
496                                         }
497                                         block_checked_in_modified = true;
498                                 }
499                         }
500                         catch(InvalidPositionException &e)
501                         {
502                                 continue;
503                         }
504                 }
505         }
506
507         /*dstream<<"spreadLight(): Changed block "
508                         <<blockchangecount<<" times"
509                         <<" for "<<from_nodes.size()<<" nodes"
510                         <<std::endl;*/
511         
512         if(lighted_nodes.size() > 0)
513                 spreadLight(bank, lighted_nodes, modified_blocks);
514 }
515
516 /*
517         A single-node source variation of the above.
518 */
519 void Map::lightNeighbors(enum LightBank bank,
520                 v3s16 pos,
521                 core::map<v3s16, MapBlock*> & modified_blocks)
522 {
523         core::map<v3s16, bool> from_nodes;
524         from_nodes.insert(pos, true);
525         spreadLight(bank, from_nodes, modified_blocks);
526 }
527
528 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
529 {
530         v3s16 dirs[6] = {
531                 v3s16(0,0,1), // back
532                 v3s16(0,1,0), // top
533                 v3s16(1,0,0), // right
534                 v3s16(0,0,-1), // front
535                 v3s16(0,-1,0), // bottom
536                 v3s16(-1,0,0), // left
537         };
538         
539         u8 brightest_light = 0;
540         v3s16 brightest_pos(0,0,0);
541         bool found_something = false;
542
543         // Loop through 6 neighbors
544         for(u16 i=0; i<6; i++){
545                 // Get the position of the neighbor node
546                 v3s16 n2pos = p + dirs[i];
547                 MapNode n2;
548                 try{
549                         n2 = getNode(n2pos);
550                 }
551                 catch(InvalidPositionException &e)
552                 {
553                         continue;
554                 }
555                 if(n2.getLight(bank) > brightest_light || found_something == false){
556                         brightest_light = n2.getLight(bank);
557                         brightest_pos = n2pos;
558                         found_something = true;
559                 }
560         }
561
562         if(found_something == false)
563                 throw InvalidPositionException();
564                 
565         return brightest_pos;
566 }
567
568 /*
569         Propagates sunlight down from a node.
570         Starting point gets sunlight.
571
572         Returns the lowest y value of where the sunlight went.
573 */
574 s16 Map::propagateSunlight(v3s16 start,
575                 core::map<v3s16, MapBlock*> & modified_blocks)
576 {
577         s16 y = start.Y;
578         for(; ; y--)
579         {
580                 v3s16 pos(start.X, y, start.Z);
581                 
582                 v3s16 blockpos = getNodeBlockPos(pos);
583                 MapBlock *block;
584                 try{
585                         block = getBlockNoCreate(blockpos);
586                 }
587                 catch(InvalidPositionException &e)
588                 {
589                         break;
590                 }
591
592                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
593                 MapNode n = block->getNode(relpos);
594
595                 if(n.sunlight_propagates())
596                 {
597                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
598                         block->setNode(relpos, n);
599
600                         modified_blocks.insert(blockpos, block);
601                 }
602                 else{
603                         break;
604                 }
605         }
606         return y + 1;
607 }
608
609 void Map::updateLighting(enum LightBank bank,
610                 core::map<v3s16, MapBlock*> & a_blocks,
611                 core::map<v3s16, MapBlock*> & modified_blocks)
612 {
613         /*m_dout<<DTIME<<"Map::updateLighting(): "
614                         <<a_blocks.getSize()<<" blocks... ";*/
615         
616         // For debugging
617         bool debug=false;
618         u32 count_was = modified_blocks.size();
619
620         core::map<v3s16, bool> light_sources;
621         
622         core::map<v3s16, u8> unlight_from;
623                 
624         core::map<v3s16, MapBlock*>::Iterator i;
625         i = a_blocks.getIterator();
626         for(; i.atEnd() == false; i++)
627         {
628                 MapBlock *block = i.getNode()->getValue();
629                 
630                 for(;;)
631                 {
632                         // Don't bother with dummy blocks.
633                         if(block->isDummy())
634                                 break;
635                 
636                         v3s16 pos = block->getPos();
637                         modified_blocks.insert(pos, block);
638
639                         /*
640                                 Clear all light from block
641                         */
642                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
643                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
644                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
645                         {
646                                 
647                                 try{
648                                         v3s16 p(x,y,z);
649                                         MapNode n = block->getNode(v3s16(x,y,z));
650                                         u8 oldlight = n.getLight(bank);
651                                         n.setLight(bank, 0);
652                                         block->setNode(v3s16(x,y,z), n);
653                                         
654                                         // Collect borders for unlighting
655                                         if(x==0 || x == MAP_BLOCKSIZE-1
656                                         || y==0 || y == MAP_BLOCKSIZE-1
657                                         || z==0 || z == MAP_BLOCKSIZE-1)
658                                         {
659                                                 v3s16 p_map = p + v3s16(
660                                                                 MAP_BLOCKSIZE*pos.X,
661                                                                 MAP_BLOCKSIZE*pos.Y,
662                                                                 MAP_BLOCKSIZE*pos.Z);
663                                                 unlight_from.insert(p_map, oldlight);
664                                         }
665                                 }
666                                 catch(InvalidPositionException &e)
667                                 {
668                                         /*
669                                                 This would happen when dealing with a
670                                                 dummy block.
671                                         */
672                                         //assert(0);
673                                         dstream<<"updateLighting(): InvalidPositionException"
674                                                         <<std::endl;
675                                 }
676                         }
677                         
678                         if(bank == LIGHTBANK_DAY)
679                         {
680                                 bool bottom_valid = block->propagateSunlight(light_sources);
681
682                                 // If bottom is valid, we're done.
683                                 if(bottom_valid)
684                                         break;
685                         }
686                         else if(bank == LIGHTBANK_NIGHT)
687                         {
688                                 break;
689                         }
690                         else
691                         {
692                                 assert(0);
693                         }
694                                 
695                         /*dstream<<"Bottom for sunlight-propagated block ("
696                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
697                                         <<std::endl;*/
698
699                         // Else get the block below and loop to it
700
701                         pos.Y--;
702                         try{
703                                 block = getBlockNoCreate(pos);
704                         }
705                         catch(InvalidPositionException &e)
706                         {
707                                 assert(0);
708                         }
709                         
710                 }
711         }
712         
713         {
714                 //TimeTaker timer("unspreadLight");
715                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
716         }
717         
718         if(debug)
719         {
720                 u32 diff = modified_blocks.size() - count_was;
721                 count_was = modified_blocks.size();
722                 dstream<<"unspreadLight modified "<<diff<<std::endl;
723         }
724
725         // TODO: Spread light from propagated sunlight?
726         // Yes, add it to light_sources... somehow.
727         // It has to be added at somewhere above, in the loop.
728         // TODO
729         // NOTE: This actually works fine without doing so
730         //       - Find out why it works
731
732         {
733                 //TimeTaker timer("spreadLight");
734                 spreadLight(bank, light_sources, modified_blocks);
735         }
736         
737         if(debug)
738         {
739                 u32 diff = modified_blocks.size() - count_was;
740                 count_was = modified_blocks.size();
741                 dstream<<"spreadLight modified "<<diff<<std::endl;
742         }
743
744         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
745 }
746
747 void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
748                 core::map<v3s16, MapBlock*> & modified_blocks)
749 {
750         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
751         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
752         
753         /*
754                 Update information about whether day and night light differ
755         */
756         for(core::map<v3s16, MapBlock*>::Iterator
757                         i = modified_blocks.getIterator();
758                         i.atEnd() == false; i++)
759         {
760                 MapBlock *block = i.getNode()->getValue();
761                 block->updateDayNightDiff();
762         }
763 }
764
765 /*
766         This is called after changing a node from transparent to opaque.
767         The lighting value of the node should be left as-is after changing
768         other values. This sets the lighting value to 0.
769 */
770 /*void Map::nodeAddedUpdate(v3s16 p, u8 lightwas,
771                 core::map<v3s16, MapBlock*> &modified_blocks)*/
772 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
773                 core::map<v3s16, MapBlock*> &modified_blocks)
774 {
775         /*PrintInfo(m_dout);
776         m_dout<<DTIME<<"Map::nodeAddedUpdate(): p=("
777                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
778
779         /*
780                 From this node to nodes underneath:
781                 If lighting is sunlight (1.0), unlight neighbours and
782                 set lighting to 0.
783                 Else discontinue.
784         */
785
786         v3s16 toppos = p + v3s16(0,1,0);
787         v3s16 bottompos = p + v3s16(0,-1,0);
788
789         bool node_under_sunlight = true;
790         core::map<v3s16, bool> light_sources;
791
792         /*
793                 If there is a node at top and it doesn't have sunlight,
794                 there has not been any sunlight going down.
795
796                 Otherwise there probably is.
797         */
798         try{
799                 MapNode topnode = getNode(toppos);
800
801                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
802                         node_under_sunlight = false;
803         }
804         catch(InvalidPositionException &e)
805         {
806         }
807         
808         if(n.d != CONTENT_TORCH)
809         {
810                 /*
811                         If there is grass below, change it to mud
812                 */
813                 try{
814                         MapNode bottomnode = getNode(bottompos);
815                         
816                         if(bottomnode.d == CONTENT_GRASS
817                                         || bottomnode.d == CONTENT_GRASS_FOOTSTEPS)
818                         {
819                                 bottomnode.d = CONTENT_MUD;
820                                 setNode(bottompos, bottomnode);
821                         }
822                 }
823                 catch(InvalidPositionException &e)
824                 {
825                 }
826         }
827
828         enum LightBank banks[] =
829         {
830                 LIGHTBANK_DAY,
831                 LIGHTBANK_NIGHT
832         };
833         for(s32 i=0; i<2; i++)
834         {
835                 enum LightBank bank = banks[i];
836
837                 u8 lightwas = getNode(p).getLight(bank);
838
839                 // Add the block of the added node to modified_blocks
840                 v3s16 blockpos = getNodeBlockPos(p);
841                 MapBlock * block = getBlockNoCreate(blockpos);
842                 assert(block != NULL);
843                 modified_blocks.insert(blockpos, block);
844                 
845                 if(isValidPosition(p) == false)
846                         throw;
847                         
848                 // Unlight neighbours of node.
849                 // This means setting light of all consequent dimmer nodes
850                 // to 0.
851                 // This also collects the nodes at the border which will spread
852                 // light again into this.
853                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
854
855                 n.setLight(bank, 0);
856         }
857         
858         setNode(p, n);
859         
860         /*
861                 If node is under sunlight, take all sunlighted nodes under
862                 it and clear light from them and from where the light has
863                 been spread.
864                 TODO: This could be optimized by mass-unlighting instead
865                       of looping
866         */
867         if(node_under_sunlight)
868         {
869                 s16 y = p.Y - 1;
870                 for(;; y--){
871                         //m_dout<<DTIME<<"y="<<y<<std::endl;
872                         v3s16 n2pos(p.X, y, p.Z);
873                         
874                         MapNode n2;
875                         try{
876                                 n2 = getNode(n2pos);
877                         }
878                         catch(InvalidPositionException &e)
879                         {
880                                 break;
881                         }
882
883                         if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
884                         {
885                                 //m_dout<<DTIME<<"doing"<<std::endl;
886                                 unLightNeighbors(LIGHTBANK_DAY,
887                                                 n2pos, n2.getLight(LIGHTBANK_DAY),
888                                                 light_sources, modified_blocks);
889                                 n2.setLight(LIGHTBANK_DAY, 0);
890                                 setNode(n2pos, n2);
891                         }
892                         else
893                                 break;
894                 }
895         }
896         
897         for(s32 i=0; i<2; i++)
898         {
899                 enum LightBank bank = banks[i];
900                 
901                 /*
902                         Spread light from all nodes that might be capable of doing so
903                         TODO: Convert to spreadLight
904                 */
905                 spreadLight(bank, light_sources, modified_blocks);
906         }
907
908         /*
909                 Update information about whether day and night light differ
910         */
911         for(core::map<v3s16, MapBlock*>::Iterator
912                         i = modified_blocks.getIterator();
913                         i.atEnd() == false; i++)
914         {
915                 MapBlock *block = i.getNode()->getValue();
916                 block->updateDayNightDiff();
917         }
918 }
919
920 /*
921 */
922 void Map::removeNodeAndUpdate(v3s16 p,
923                 core::map<v3s16, MapBlock*> &modified_blocks)
924 {
925         /*PrintInfo(m_dout);
926         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
927                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
928         
929         bool node_under_sunlight = true;
930         
931         v3s16 toppos = p + v3s16(0,1,0);
932
933         // Node will be replaced with this
934         u8 replace_material = CONTENT_AIR;
935         
936         /*
937                 If there is a node at top and it doesn't have sunlight,
938                 there will be no sunlight going down.
939         */
940         try{
941                 MapNode topnode = getNode(toppos);
942
943                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
944                         node_under_sunlight = false;
945         }
946         catch(InvalidPositionException &e)
947         {
948         }
949
950         core::map<v3s16, bool> light_sources;
951
952         enum LightBank banks[] =
953         {
954                 LIGHTBANK_DAY,
955                 LIGHTBANK_NIGHT
956         };
957         for(s32 i=0; i<2; i++)
958         {
959                 enum LightBank bank = banks[i];
960         
961                 /*
962                         Unlight neighbors (in case the node is a light source)
963                 */
964                 unLightNeighbors(bank, p,
965                                 getNode(p).getLight(bank),
966                                 light_sources, modified_blocks);
967         }
968
969         /*
970                 Remove the node.
971                 This also clears the lighting.
972         */
973
974         MapNode n;
975         n.d = replace_material;
976         setNode(p, n);
977         
978         for(s32 i=0; i<2; i++)
979         {
980                 enum LightBank bank = banks[i];
981         
982                 /*
983                         Recalculate lighting
984                 */
985                 spreadLight(bank, light_sources, modified_blocks);
986         }
987
988         // Add the block of the removed node to modified_blocks
989         v3s16 blockpos = getNodeBlockPos(p);
990         MapBlock * block = getBlockNoCreate(blockpos);
991         assert(block != NULL);
992         modified_blocks.insert(blockpos, block);
993
994         /*
995                 If the removed node was under sunlight, propagate the
996                 sunlight down from it and then light all neighbors
997                 of the propagated blocks.
998         */
999         if(node_under_sunlight)
1000         {
1001                 s16 ybottom = propagateSunlight(p, modified_blocks);
1002                 /*m_dout<<DTIME<<"Node was under sunlight. "
1003                                 "Propagating sunlight";
1004                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1005                 s16 y = p.Y;
1006                 for(; y >= ybottom; y--)
1007                 {
1008                         v3s16 p2(p.X, y, p.Z);
1009                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1010                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1011                                         <<std::endl;*/
1012                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1013                 }
1014         }
1015         else
1016         {
1017                 // Set the lighting of this node to 0
1018                 // TODO: Is this needed? Lighting is cleared up there already.
1019                 try{
1020                         MapNode n = getNode(p);
1021                         n.setLight(LIGHTBANK_DAY, 0);
1022                         setNode(p, n);
1023                 }
1024                 catch(InvalidPositionException &e)
1025                 {
1026                         throw;
1027                 }
1028         }
1029
1030         for(s32 i=0; i<2; i++)
1031         {
1032                 enum LightBank bank = banks[i];
1033         
1034                 // Get the brightest neighbour node and propagate light from it
1035                 v3s16 n2p = getBrightestNeighbour(bank, p);
1036                 try{
1037                         MapNode n2 = getNode(n2p);
1038                         lightNeighbors(bank, n2p, modified_blocks);
1039                 }
1040                 catch(InvalidPositionException &e)
1041                 {
1042                 }
1043         }
1044
1045         /*
1046                 Update information about whether day and night light differ
1047         */
1048         for(core::map<v3s16, MapBlock*>::Iterator
1049                         i = modified_blocks.getIterator();
1050                         i.atEnd() == false; i++)
1051         {
1052                 MapBlock *block = i.getNode()->getValue();
1053                 block->updateDayNightDiff();
1054         }
1055 }
1056
1057 #ifndef SERVER
1058 void Map::expireMeshes(bool only_daynight_diffed)
1059 {
1060         TimeTaker timer("expireMeshes()");
1061
1062         core::map<v2s16, MapSector*>::Iterator si;
1063         si = m_sectors.getIterator();
1064         for(; si.atEnd() == false; si++)
1065         {
1066                 MapSector *sector = si.getNode()->getValue();
1067
1068                 core::list< MapBlock * > sectorblocks;
1069                 sector->getBlocks(sectorblocks);
1070                 
1071                 core::list< MapBlock * >::Iterator i;
1072                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1073                 {
1074                         MapBlock *block = *i;
1075
1076                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
1077                         {
1078                                 continue;
1079                         }
1080                         
1081                         {
1082                                 JMutexAutoLock lock(block->mesh_mutex);
1083                                 if(block->mesh != NULL)
1084                                 {
1085                                         /*block->mesh->drop();
1086                                         block->mesh = NULL;*/
1087                                         block->setMeshExpired(true);
1088                                 }
1089                         }
1090                 }
1091         }
1092 }
1093
1094 void Map::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
1095 {
1096         assert(mapType() == MAPTYPE_CLIENT);
1097
1098         try{
1099                 v3s16 p = blockpos + v3s16(0,0,0);
1100                 MapBlock *b = getBlockNoCreate(p);
1101                 b->updateMesh(daynight_ratio);
1102         }
1103         catch(InvalidPositionException &e){}
1104         // Leading edge
1105         try{
1106                 v3s16 p = blockpos + v3s16(-1,0,0);
1107                 MapBlock *b = getBlockNoCreate(p);
1108                 b->updateMesh(daynight_ratio);
1109         }
1110         catch(InvalidPositionException &e){}
1111         try{
1112                 v3s16 p = blockpos + v3s16(0,-1,0);
1113                 MapBlock *b = getBlockNoCreate(p);
1114                 b->updateMesh(daynight_ratio);
1115         }
1116         catch(InvalidPositionException &e){}
1117         try{
1118                 v3s16 p = blockpos + v3s16(0,0,-1);
1119                 MapBlock *b = getBlockNoCreate(p);
1120                 b->updateMesh(daynight_ratio);
1121         }
1122         catch(InvalidPositionException &e){}
1123         /*// Trailing edge
1124         try{
1125                 v3s16 p = blockpos + v3s16(1,0,0);
1126                 MapBlock *b = getBlockNoCreate(p);
1127                 b->updateMesh(daynight_ratio);
1128         }
1129         catch(InvalidPositionException &e){}
1130         try{
1131                 v3s16 p = blockpos + v3s16(0,1,0);
1132                 MapBlock *b = getBlockNoCreate(p);
1133                 b->updateMesh(daynight_ratio);
1134         }
1135         catch(InvalidPositionException &e){}
1136         try{
1137                 v3s16 p = blockpos + v3s16(0,0,1);
1138                 MapBlock *b = getBlockNoCreate(p);
1139                 b->updateMesh(daynight_ratio);
1140         }
1141         catch(InvalidPositionException &e){}*/
1142 }
1143
1144 #endif
1145
1146 bool Map::dayNightDiffed(v3s16 blockpos)
1147 {
1148         try{
1149                 v3s16 p = blockpos + v3s16(0,0,0);
1150                 MapBlock *b = getBlockNoCreate(p);
1151                 if(b->dayNightDiffed())
1152                         return true;
1153         }
1154         catch(InvalidPositionException &e){}
1155         // Leading edges
1156         try{
1157                 v3s16 p = blockpos + v3s16(-1,0,0);
1158                 MapBlock *b = getBlockNoCreate(p);
1159                 if(b->dayNightDiffed())
1160                         return true;
1161         }
1162         catch(InvalidPositionException &e){}
1163         try{
1164                 v3s16 p = blockpos + v3s16(0,-1,0);
1165                 MapBlock *b = getBlockNoCreate(p);
1166                 if(b->dayNightDiffed())
1167                         return true;
1168         }
1169         catch(InvalidPositionException &e){}
1170         try{
1171                 v3s16 p = blockpos + v3s16(0,0,-1);
1172                 MapBlock *b = getBlockNoCreate(p);
1173                 if(b->dayNightDiffed())
1174                         return true;
1175         }
1176         catch(InvalidPositionException &e){}
1177         // Trailing edges
1178         try{
1179                 v3s16 p = blockpos + v3s16(1,0,0);
1180                 MapBlock *b = getBlockNoCreate(p);
1181                 if(b->dayNightDiffed())
1182                         return true;
1183         }
1184         catch(InvalidPositionException &e){}
1185         try{
1186                 v3s16 p = blockpos + v3s16(0,1,0);
1187                 MapBlock *b = getBlockNoCreate(p);
1188                 if(b->dayNightDiffed())
1189                         return true;
1190         }
1191         catch(InvalidPositionException &e){}
1192         try{
1193                 v3s16 p = blockpos + v3s16(0,0,1);
1194                 MapBlock *b = getBlockNoCreate(p);
1195                 if(b->dayNightDiffed())
1196                         return true;
1197         }
1198         catch(InvalidPositionException &e){}
1199
1200         return false;
1201 }
1202
1203 /*
1204         Updates usage timers
1205 */
1206 void Map::timerUpdate(float dtime)
1207 {
1208         JMutexAutoLock lock(m_sector_mutex);
1209
1210         core::map<v2s16, MapSector*>::Iterator si;
1211
1212         si = m_sectors.getIterator();
1213         for(; si.atEnd() == false; si++)
1214         {
1215                 MapSector *sector = si.getNode()->getValue();
1216                 sector->usage_timer += dtime;
1217         }
1218 }
1219
1220 void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
1221 {
1222         /*
1223                 Wait for caches to be removed before continuing.
1224                 
1225                 This disables the existence of caches while locked
1226         */
1227         SharedPtr<JMutexAutoLock> cachelock(m_blockcachelock.waitCaches());
1228
1229         core::list<v2s16>::Iterator j;
1230         for(j=list.begin(); j!=list.end(); j++)
1231         {
1232                 MapSector *sector = m_sectors[*j];
1233                 if(only_blocks)
1234                 {
1235                         sector->deleteBlocks();
1236                 }
1237                 else
1238                 {
1239                         /*
1240                                 If sector is in sector cache, remove it from there
1241                         */
1242                         if(m_sector_cache == sector)
1243                         {
1244                                 m_sector_cache = NULL;
1245                         }
1246                         /*
1247                                 Remove from map and delete
1248                         */
1249                         m_sectors.remove(*j);
1250                         delete sector;
1251                 }
1252         }
1253 }
1254
1255 u32 Map::deleteUnusedSectors(float timeout, bool only_blocks,
1256                 core::list<v3s16> *deleted_blocks)
1257 {
1258         JMutexAutoLock lock(m_sector_mutex);
1259
1260         core::list<v2s16> sector_deletion_queue;
1261         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
1262         for(; i.atEnd() == false; i++)
1263         {
1264                 MapSector *sector = i.getNode()->getValue();
1265                 /*
1266                         Delete sector from memory if it hasn't been used in a long time
1267                 */
1268                 if(sector->usage_timer > timeout)
1269                 {
1270                         sector_deletion_queue.push_back(i.getNode()->getKey());
1271                         
1272                         if(deleted_blocks != NULL)
1273                         {
1274                                 // Collect positions of blocks of sector
1275                                 MapSector *sector = i.getNode()->getValue();
1276                                 core::list<MapBlock*> blocks;
1277                                 sector->getBlocks(blocks);
1278                                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1279                                                 i != blocks.end(); i++)
1280                                 {
1281                                         deleted_blocks->push_back((*i)->getPos());
1282                                 }
1283                         }
1284                 }
1285         }
1286         deleteSectors(sector_deletion_queue, only_blocks);
1287         return sector_deletion_queue.getSize();
1288 }
1289
1290 void Map::PrintInfo(std::ostream &out)
1291 {
1292         out<<"Map: ";
1293 }
1294
1295 /*
1296         ServerMap
1297 */
1298
1299 ServerMap::ServerMap(std::string savedir, HMParams hmp, MapParams mp):
1300         Map(dout_server),
1301         m_heightmap(NULL)
1302 {
1303         m_savedir = savedir;
1304         m_map_saving_enabled = false;
1305         
1306         try
1307         {
1308                 // If directory exists, check contents and load if possible
1309                 if(fs::PathExists(m_savedir))
1310                 {
1311                         // If directory is empty, it is safe to save into it.
1312                         if(fs::GetDirListing(m_savedir).size() == 0)
1313                         {
1314                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1315                                                 <<std::endl;
1316                                 m_map_saving_enabled = true;
1317                         }
1318                         else
1319                         {
1320                                 // Load master heightmap
1321                                 loadMasterHeightmap();
1322                                 
1323                                 // Load sector (0,0) and throw and exception on fail
1324                                 if(loadSectorFull(v2s16(0,0)) == false)
1325                                         throw LoadError("Failed to load sector (0,0)");
1326
1327                                 dstream<<DTIME<<"Server: Successfully loaded master "
1328                                                 "heightmap and sector (0,0) from "<<savedir<<
1329                                                 ", assuming valid save directory."
1330                                                 <<std::endl;
1331
1332                                 m_map_saving_enabled = true;
1333                                 // Map loaded, not creating new one
1334                                 return;
1335                         }
1336                 }
1337                 // If directory doesn't exist, it is safe to save to it
1338                 else{
1339                         m_map_saving_enabled = true;
1340                 }
1341         }
1342         catch(std::exception &e)
1343         {
1344                 dstream<<DTIME<<"Server: Failed to load map from "<<savedir
1345                                 <<", exception: "<<e.what()<<std::endl;
1346                 dstream<<DTIME<<"Please remove the map or fix it."<<std::endl;
1347                 dstream<<DTIME<<"WARNING: Map saving will be disabled."<<std::endl;
1348         }
1349
1350         dstream<<DTIME<<"Initializing new map."<<std::endl;
1351         
1352         // Create master heightmap
1353         ValueGenerator *maxgen =
1354                         ValueGenerator::deSerialize(hmp.randmax);
1355         ValueGenerator *factorgen =
1356                         ValueGenerator::deSerialize(hmp.randfactor);
1357         ValueGenerator *basegen =
1358                         ValueGenerator::deSerialize(hmp.base);
1359         m_heightmap = new UnlimitedHeightmap
1360                         (hmp.blocksize, maxgen, factorgen, basegen);
1361         
1362         // Set map parameters
1363         m_params = mp;
1364         
1365         // Create zero sector
1366         emergeSector(v2s16(0,0));
1367
1368         // Initially write whole map
1369         save(false);
1370 }
1371
1372 ServerMap::~ServerMap()
1373 {
1374         try
1375         {
1376                 if(m_map_saving_enabled)
1377                 {
1378                         //save(false);
1379                         // Save only changed parts
1380                         save(true);
1381                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1382                 }
1383                 else
1384                 {
1385                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1386                 }
1387         }
1388         catch(std::exception &e)
1389         {
1390                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1391                                 <<", exception: "<<e.what()<<std::endl;
1392         }
1393         
1394         if(m_heightmap != NULL)
1395                 delete m_heightmap;
1396 }
1397
1398 MapSector * ServerMap::emergeSector(v2s16 p2d)
1399 {
1400         DSTACK("%s: p2d=(%d,%d)",
1401                         __FUNCTION_NAME,
1402                         p2d.X, p2d.Y);
1403         // Check that it doesn't exist already
1404         try{
1405                 return getSectorNoGenerate(p2d);
1406         }
1407         catch(InvalidPositionException &e)
1408         {
1409         }
1410         
1411         /*
1412                 Try to load the sector from disk.
1413         */
1414         if(loadSectorFull(p2d) == true)
1415         {
1416                 return getSectorNoGenerate(p2d);
1417         }
1418
1419         /*
1420                 If there is no master heightmap, throw.
1421         */
1422         if(m_heightmap == NULL)
1423         {
1424                 throw InvalidPositionException("emergeSector(): no heightmap");
1425         }
1426
1427         /*
1428                 Do not generate over-limit
1429         */
1430         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1431         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1432         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
1433         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
1434                 throw InvalidPositionException("emergeSector(): pos. over limit");
1435
1436         /*
1437                 Generate sector and heightmaps
1438         */
1439         
1440         // Number of heightmaps in sector in each direction
1441         u16 hm_split = SECTOR_HEIGHTMAP_SPLIT;
1442
1443         // Heightmap side width
1444         s16 hm_d = MAP_BLOCKSIZE / hm_split;
1445
1446         ServerMapSector *sector = new ServerMapSector(this, p2d, hm_split);
1447
1448         /*dstream<<"Generating sector ("<<p2d.X<<","<<p2d.Y<<")"
1449                         " heightmaps and objects"<<std::endl;*/
1450         
1451         // Loop through sub-heightmaps
1452         for(s16 y=0; y<hm_split; y++)
1453         for(s16 x=0; x<hm_split; x++)
1454         {
1455                 v2s16 p_in_sector = v2s16(x,y);
1456                 v2s16 mhm_p = p2d * hm_split + p_in_sector;
1457                 f32 corners[4] = {
1458                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)),
1459                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)),
1460                         m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)),
1461                         m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)),
1462                 };
1463
1464                 /*dstream<<"p_in_sector=("<<p_in_sector.X<<","<<p_in_sector.Y<<")"
1465                                 <<" mhm_p=("<<mhm_p.X<<","<<mhm_p.Y<<")"
1466                                 <<std::endl;*/
1467
1468                 FixedHeightmap *hm = new FixedHeightmap(&m_hwrapper,
1469                                 mhm_p, hm_d);
1470                 sector->setHeightmap(p_in_sector, hm);
1471
1472                 //TODO: Make these values configurable
1473                 //hm->generateContinued(0.0, 0.0, corners);
1474                 hm->generateContinued(0.5, 0.2, corners);
1475                 //hm->generateContinued(1.0, 0.2, corners);
1476                 //hm->generateContinued(2.0, 0.2, corners);
1477
1478                 //hm->print();
1479                 
1480         }
1481
1482         /*
1483                 Generate objects
1484         */
1485         
1486         core::map<v3s16, u8> *objects = new core::map<v3s16, u8>;
1487         sector->setObjects(objects);
1488         
1489         v2s16 mhm_p = p2d * hm_split;
1490         f32 corners[4] = {
1491                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,0)*hm_split),
1492                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,0)*hm_split),
1493                 m_heightmap->getGroundHeight(mhm_p+v2s16(1,1)*hm_split),
1494                 m_heightmap->getGroundHeight(mhm_p+v2s16(0,1)*hm_split),
1495         };
1496         
1497         float avgheight = (corners[0]+corners[1]+corners[2]+corners[3])/4.0;
1498         float avgslope = 0.0;
1499         avgslope += fabs(avgheight - corners[0]);
1500         avgslope += fabs(avgheight - corners[1]);
1501         avgslope += fabs(avgheight - corners[2]);
1502         avgslope += fabs(avgheight - corners[3]);
1503         avgslope /= 4.0;
1504         avgslope /= MAP_BLOCKSIZE;
1505         //dstream<<"avgslope="<<avgslope<<std::endl;
1506
1507         float pitness = 0.0;
1508         v2f32 a;
1509         a = m_heightmap->getSlope(p2d+v2s16(0,0));
1510         pitness += -a.X;
1511         pitness += -a.Y;
1512         a = m_heightmap->getSlope(p2d+v2s16(0,1));
1513         pitness += -a.X;
1514         pitness += a.Y;
1515         a = m_heightmap->getSlope(p2d+v2s16(1,1));
1516         pitness += a.X;
1517         pitness += a.Y;
1518         a = m_heightmap->getSlope(p2d+v2s16(1,0));
1519         pitness += a.X;
1520         pitness += -a.Y;
1521         pitness /= 4.0;
1522         pitness /= MAP_BLOCKSIZE;
1523         //dstream<<"pitness="<<pitness<<std::endl;
1524         
1525         /*
1526                 Plant some trees if there is not much slope
1527         */
1528         {
1529                 // Avgslope is the derivative of a hill
1530                 float t = avgslope * avgslope;
1531                 float a = MAP_BLOCKSIZE * m_params.plants_amount;
1532                 u32 tree_max;
1533                 if(t > 0.03)
1534                         tree_max = a / (t/0.03);
1535                 else
1536                         tree_max = a;
1537                 u32 count = (myrand()%(tree_max+1));
1538                 //u32 count = tree_max;
1539                 for(u32 i=0; i<count; i++)
1540                 {
1541                         s16 x = (myrand()%(MAP_BLOCKSIZE-2))+1;
1542                         s16 z = (myrand()%(MAP_BLOCKSIZE-2))+1;
1543                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1544                         if(y < WATER_LEVEL)
1545                                 continue;
1546                         objects->insert(v3s16(x, y, z),
1547                                         SECTOR_OBJECT_TREE_1);
1548                 }
1549         }
1550         /*
1551                 Plant some bushes if sector is pit-like
1552         */
1553         {
1554                 // Pitness usually goes at around -0.5...0.5
1555                 u32 bush_max = 0;
1556                 u32 a = MAP_BLOCKSIZE * 3.0 * m_params.plants_amount;
1557                 if(pitness > 0)
1558                         bush_max = (pitness*a*4);
1559                 if(bush_max > a)
1560                         bush_max = a;
1561                 u32 count = (myrand()%(bush_max+1));
1562                 for(u32 i=0; i<count; i++)
1563                 {
1564                         s16 x = myrand()%(MAP_BLOCKSIZE-0)+0;
1565                         s16 z = myrand()%(MAP_BLOCKSIZE-0)+0;
1566                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1567                         if(y < WATER_LEVEL)
1568                                 continue;
1569                         objects->insert(v3s16(x, y, z),
1570                                         SECTOR_OBJECT_BUSH_1);
1571                 }
1572         }
1573         /*
1574                 Add ravine (randomly)
1575         */
1576         if(m_params.ravines_amount != 0)
1577         {
1578                 if(myrand()%(s32)(20.0 / m_params.ravines_amount) == 0)
1579                 {
1580                         s16 s = 6;
1581                         s16 x = myrand()%(MAP_BLOCKSIZE-s*2-1)+s;
1582                         s16 z = myrand()%(MAP_BLOCKSIZE-s*2-1)+s;
1583                         /*s16 x = 8;
1584                         s16 z = 8;*/
1585                         s16 y = sector->getGroundHeight(v2s16(x,z))+1;
1586                         objects->insert(v3s16(x, y, z),
1587                                         SECTOR_OBJECT_RAVINE);
1588                 }
1589         }
1590
1591         /*
1592                 Insert to container
1593         */
1594         JMutexAutoLock lock(m_sector_mutex);
1595         m_sectors.insert(p2d, sector);
1596         
1597         return sector;
1598 }
1599
1600 MapBlock * ServerMap::emergeBlock(
1601                 v3s16 p,
1602                 bool only_from_disk,
1603                 core::map<v3s16, MapBlock*> &changed_blocks,
1604                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
1605 )
1606 {
1607         DSTACK("%s: p=(%d,%d,%d), only_from_disk=%d",
1608                         __FUNCTION_NAME,
1609                         p.X, p.Y, p.Z, only_from_disk);
1610                         
1611         /*dstream<<"ServerMap::emergeBlock(): "
1612                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
1613                         <<", only_from_disk="<<only_from_disk<<std::endl;*/
1614         v2s16 p2d(p.X, p.Z);
1615         s16 block_y = p.Y;
1616         /*
1617                 This will create or load a sector if not found in memory.
1618                 If block exists on disk, it will be loaded.
1619
1620                 NOTE: On old save formats, this will be slow, as it generates
1621                       lighting on blocks for them.
1622         */
1623         ServerMapSector *sector = (ServerMapSector*)emergeSector(p2d);
1624         assert(sector->getId() == MAPSECTOR_SERVER);
1625
1626         // Try to get a block from the sector
1627         MapBlock *block = NULL;
1628         bool not_on_disk = false;
1629         try{
1630                 block = sector->getBlockNoCreate(block_y);
1631                 if(block->isDummy() == true)
1632                         not_on_disk = true;
1633                 else
1634                         return block;
1635         }
1636         catch(InvalidPositionException &e)
1637         {
1638                 not_on_disk = true;
1639         }
1640         
1641         /*
1642                 If block was not found on disk and not going to generate a
1643                 new one, make sure there is a dummy block in place.
1644         */
1645         if(not_on_disk && only_from_disk)
1646         {
1647                 if(block == NULL)
1648                 {
1649                         // Create dummy block
1650                         block = new MapBlock(this, p, true);
1651
1652                         // Add block to sector
1653                         sector->insertBlock(block);
1654                 }
1655                 // Done.
1656                 return block;
1657         }
1658
1659         //dstream<<"Not found on disk, generating."<<std::endl;
1660         //TimeTaker("emergeBlock()", g_irrlicht);
1661
1662         /*
1663                 Do not generate over-limit
1664         */
1665         if(blockpos_over_limit(p))
1666                 throw InvalidPositionException("emergeBlock(): pos. over limit");
1667
1668         /*
1669                 OK; Not found.
1670
1671                 Go on generating the block.
1672
1673                 TODO: If a dungeon gets generated so that it's side gets
1674                       revealed to the outside air, the lighting should be
1675                           recalculated.
1676         */
1677         
1678         /*
1679                 If block doesn't exist, create one.
1680                 If it exists, it is a dummy. In that case unDummify() it.
1681         */
1682         if(block == NULL)
1683         {
1684                 block = sector->createBlankBlockNoInsert(block_y);
1685         }
1686         else
1687         {
1688                 // Remove the block so that nobody can get a half-generated one.
1689                 sector->removeBlock(block);
1690                 // Allocate the block to be a proper one.
1691                 block->unDummify();
1692         }
1693         
1694 #if 0
1695         /*
1696                 Initialize dungeon making by creating a random table
1697         */
1698         const s32 ued_max = 5;
1699         const s32 ued_min = 3;
1700         bool underground_emptiness[ued_max*ued_max*ued_max];
1701         s32 ued = (myrand()%(ued_max-ued_min+1))+1;
1702         //s32 ued = ued_max;
1703         for(s32 i=0; i<ued*ued*ued; i++)
1704         {
1705                 underground_emptiness[i] = ((myrand() % 5) == 0);
1706         }
1707
1708         /*
1709                 This is a messy hack to sort the emptiness a bit
1710         */
1711         // Iterator through a few times
1712         for(s32 j=0; j<2; j++)
1713         for(s32 y0=0; y0<ued; y0++)
1714         for(s32 z0=0; z0<ued; z0++)
1715         for(s32 x0=0; x0<ued; x0++)
1716         {
1717                 v3s16 p0(x0,y0,z0);
1718                 bool &e0 = underground_emptiness[
1719                                 ued*ued*(z0*ued/MAP_BLOCKSIZE)
1720                                 +ued*(y0*ued/MAP_BLOCKSIZE)
1721                                 +(x0*ued/MAP_BLOCKSIZE)];
1722                                 
1723                 v3s16 dirs[6] = {
1724                         v3s16(0,0,1), // back
1725                         v3s16(1,0,0), // right
1726                         v3s16(0,0,-1), // front
1727                         v3s16(-1,0,0), // left
1728                         /*v3s16(0,1,0), // top
1729                         v3s16(0,-1,0), // bottom*/
1730                 };
1731
1732                 for(s32 i=0; i<4; i++)
1733                 {
1734                         v3s16 p1 = p0 + dirs[i];
1735                         if(isInArea(p1, ued) == false)
1736                                 continue;
1737                         bool &e1 = underground_emptiness[
1738                                         ued*ued*(p1.Z*ued/MAP_BLOCKSIZE)
1739                                         +ued*(p1.Y*ued/MAP_BLOCKSIZE)
1740                                         +(p1.X*ued/MAP_BLOCKSIZE)];
1741                         if(e0 == e1)
1742                                 continue;
1743                                 
1744                         v3s16 dirs[6] = {
1745                                 v3s16(0,1,0), // top
1746                                 v3s16(0,-1,0), // bottom
1747                                 /*v3s16(0,0,1), // back
1748                                 v3s16(1,0,0), // right
1749                                 v3s16(0,0,-1), // front
1750                                 v3s16(-1,0,0), // left*/
1751                         };
1752                         for(s32 i=0; i<2; i++)
1753                         {
1754                                 v3s16 p2 = p1 + dirs[i];
1755                                 if(p2 == p0)
1756                                         continue;
1757                                 if(isInArea(p2, ued) == false)
1758                                         continue;
1759                                 bool &e2 = underground_emptiness[
1760                                                 ued*ued*(p2.Z*ued/MAP_BLOCKSIZE)
1761                                                 +ued*(p2.Y*ued/MAP_BLOCKSIZE)
1762                                                 +(p2.X*ued/MAP_BLOCKSIZE)];
1763                                 if(e2 != e0)
1764                                         continue;
1765                                 
1766                                 bool t = e1;
1767                                 e1 = e2;
1768                                 e2 = t;
1769
1770                                 break;
1771                         }
1772                         //break;
1773                 }
1774         }
1775 #endif
1776
1777         /*
1778                 Create dungeon making table
1779         */
1780         const s32 ued = MAP_BLOCKSIZE;
1781         bool underground_emptiness[ued*ued*ued];
1782         for(s32 i=0; i<ued*ued*ued; i++)
1783         {
1784                 underground_emptiness[i] = 0;
1785         }
1786         // Generate dungeons
1787         {
1788                 /*
1789                         Initialize orp and ors. Try to find if some neighboring
1790                         MapBlock has a tunnel ended in its side
1791                 */
1792
1793                 v3f orp(
1794                         (float)(myrand()%ued)+0.5,
1795                         (float)(myrand()%ued)+0.5,
1796                         (float)(myrand()%ued)+0.5
1797                 );
1798
1799                 // Check z-
1800                 try
1801                 {
1802                         s16 z = -1;
1803                         for(s16 y=0; y<ued; y++)
1804                         for(s16 x=0; x<ued; x++)
1805                         {
1806                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
1807                                 if(getNode(ap).d == CONTENT_AIR)
1808                                 {
1809                                         orp = v3f(x+1,y+1,0);
1810                                         goto continue_generating;
1811                                 }
1812                         }
1813                 }
1814                 catch(InvalidPositionException &e){}
1815                 
1816                 // Check z+
1817                 try
1818                 {
1819                         s16 z = ued;
1820                         for(s16 y=0; y<ued; y++)
1821                         for(s16 x=0; x<ued; x++)
1822                         {
1823                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
1824                                 if(getNode(ap).d == CONTENT_AIR)
1825                                 {
1826                                         orp = v3f(x+1,y+1,ued-1);
1827                                         goto continue_generating;
1828                                 }
1829                         }
1830                 }
1831                 catch(InvalidPositionException &e){}
1832                 
1833                 // Check x-
1834                 try
1835                 {
1836                         s16 x = -1;
1837                         for(s16 y=0; y<ued; y++)
1838                         for(s16 z=0; z<ued; z++)
1839                         {
1840                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
1841                                 if(getNode(ap).d == CONTENT_AIR)
1842                                 {
1843                                         orp = v3f(0,y+1,z+1);
1844                                         goto continue_generating;
1845                                 }
1846                         }
1847                 }
1848                 catch(InvalidPositionException &e){}
1849                 
1850                 // Check x+
1851                 try
1852                 {
1853                         s16 x = ued;
1854                         for(s16 y=0; y<ued; y++)
1855                         for(s16 z=0; z<ued; z++)
1856                         {
1857                                 v3s16 ap = v3s16(x,y,z) + block->getPosRelative();
1858                                 if(getNode(ap).d == CONTENT_AIR)
1859                                 {
1860                                         orp = v3f(ued-1,y+1,z+1);
1861                                         goto continue_generating;
1862                                 }
1863                         }
1864                 }
1865                 catch(InvalidPositionException &e){}
1866
1867 continue_generating:
1868                 
1869                 /*
1870                         Generate some tunnel starting from orp and ors
1871                 */
1872                 for(u16 i=0; i<3; i++)
1873                 {
1874                         v3f rp(
1875                                 (float)(myrand()%ued)+0.5,
1876                                 (float)(myrand()%ued)+0.5,
1877                                 (float)(myrand()%ued)+0.5
1878                         );
1879                         s16 min_d = 0;
1880                         s16 max_d = 4;
1881                         s16 rs = (myrand()%(max_d-min_d+1))+min_d;
1882                         
1883                         v3f vec = rp - orp;
1884
1885                         for(float f=0; f<1.0; f+=0.04)
1886                         {
1887                                 v3f fp = orp + vec * f;
1888                                 v3s16 cp(fp.X, fp.Y, fp.Z);
1889                                 s16 d0 = -rs/2;
1890                                 s16 d1 = d0 + rs - 1;
1891                                 for(s16 z0=d0; z0<=d1; z0++)
1892                                 {
1893                                         s16 si = rs - abs(z0);
1894                                         for(s16 x0=-si; x0<=si-1; x0++)
1895                                         {
1896                                                 s16 si2 = rs - abs(x0);
1897                                                 for(s16 y0=-si2+1; y0<=si2-1; y0++)
1898                                                 {
1899                                                         s16 z = cp.Z + z0;
1900                                                         s16 y = cp.Y + y0;
1901                                                         s16 x = cp.X + x0;
1902                                                         v3s16 p(x,y,z);
1903                                                         if(isInArea(p, ued) == false)
1904                                                                 continue;
1905                                                         underground_emptiness[ued*ued*z + ued*y + x] = 1;
1906                                                 }
1907                                         }
1908                                 }
1909                         }
1910
1911                         orp = rp;
1912                 }
1913         }
1914         
1915         // This is the basic material of what the visible flat ground
1916         // will consist of
1917         u8 material = CONTENT_GRASS;
1918
1919         u8 water_material = CONTENT_WATER;
1920         if(g_settings.getBool("endless_water"))
1921                 water_material = CONTENT_OCEAN;
1922         
1923         s32 lowest_ground_y = 32767;
1924         s32 highest_ground_y = -32768;
1925         
1926         // DEBUG
1927         //sector->printHeightmaps();
1928
1929         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1930         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1931         {
1932                 //dstream<<"emergeBlock: x0="<<x0<<", z0="<<z0<<std::endl;
1933
1934                 float surface_y_f = sector->getGroundHeight(v2s16(x0,z0));
1935                 //assert(surface_y_f > GROUNDHEIGHT_VALID_MINVALUE);
1936                 if(surface_y_f < GROUNDHEIGHT_VALID_MINVALUE)
1937                 {
1938                         dstream<<"WARNING: Surface height not found in sector "
1939                                         "for block that is being emerged"<<std::endl;
1940                         surface_y_f = 0.0;
1941                 }
1942
1943                 s16 surface_y = surface_y_f;
1944                 //avg_ground_y += surface_y;
1945                 if(surface_y < lowest_ground_y)
1946                         lowest_ground_y = surface_y;
1947                 if(surface_y > highest_ground_y)
1948                         highest_ground_y = surface_y;
1949
1950                 s32 surface_depth = 0;
1951                 
1952                 float slope = sector->getSlope(v2s16(x0,z0)).getLength();
1953                 
1954                 //float min_slope = 0.45;
1955                 //float max_slope = 0.85;
1956                 float min_slope = 0.60;
1957                 float max_slope = 1.20;
1958                 float min_slope_depth = 5.0;
1959                 float max_slope_depth = 0;
1960                 if(slope < min_slope)
1961                         surface_depth = min_slope_depth;
1962                 else if(slope > max_slope)
1963                         surface_depth = max_slope_depth;
1964                 else
1965                         surface_depth = (1.-(slope-min_slope)/max_slope) * min_slope_depth;
1966
1967                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1968                 {
1969                         s16 real_y = block_y * MAP_BLOCKSIZE + y0;
1970                         MapNode n;
1971                         /*
1972                                 Calculate lighting
1973                                 
1974                                 NOTE: If there are some man-made structures above the
1975                                 newly created block, they won't be taken into account.
1976                         */
1977                         if(real_y > surface_y)
1978                                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
1979
1980                         /*
1981                                 Calculate material
1982                         */
1983
1984                         if(real_y <= surface_y - surface_depth)
1985                         {
1986                                 // Create dungeons
1987                                 if(underground_emptiness[
1988                                                 ued*ued*(z0*ued/MAP_BLOCKSIZE)
1989                                                 +ued*(y0*ued/MAP_BLOCKSIZE)
1990                                                 +(x0*ued/MAP_BLOCKSIZE)])
1991                                 {
1992                                         n.d = CONTENT_AIR;
1993                                 }
1994                                 else
1995                                 {
1996                                         n.d = CONTENT_STONE;
1997                                 }
1998                         }
1999                         // If node is at or under heightmap y
2000                         else if(real_y <= surface_y)
2001                         {
2002                                 // If under water level, it's mud
2003                                 if(real_y < WATER_LEVEL)
2004                                         n.d = CONTENT_MUD;
2005                                 // Only the topmost node is grass
2006                                 else if(real_y <= surface_y - 1)
2007                                         n.d = CONTENT_MUD;
2008                                 // Else it's the main material
2009                                 else
2010                                         n.d = material;
2011                         }
2012                         // If node is over heightmap y
2013                         else{
2014                                 // If under water level, it's water
2015                                 if(real_y < WATER_LEVEL)
2016                                 {
2017                                         n.d = water_material;
2018                                         n.setLight(LIGHTBANK_DAY,
2019                                                         diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1));
2020                                 }
2021                                 // else air
2022                                 else
2023                                         n.d = CONTENT_AIR;
2024                         }
2025                         block->setNode(v3s16(x0,y0,z0), n);
2026                 }
2027         }
2028
2029         /*
2030                 Calculate is_underground
2031         */
2032         // Probably underground if the highest part of block is under lowest
2033         // ground height
2034         bool is_underground = (block_y+1) * MAP_BLOCKSIZE <= lowest_ground_y;
2035         block->setIsUnderground(is_underground);
2036
2037         /*
2038                 Force lighting update if some part of block is underground
2039                 This is needed because of caves.
2040         */
2041         
2042         bool some_part_underground = (block_y+0) * MAP_BLOCKSIZE < highest_ground_y;
2043         if(some_part_underground)
2044         //if(is_underground)
2045         {
2046                 lighting_invalidated_blocks[block->getPos()] = block;
2047         }
2048         
2049         /*
2050                 Add some minerals
2051         */
2052
2053         if(some_part_underground)
2054         {
2055                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
2056
2057                 /*
2058                         Add meseblocks
2059                 */
2060                 for(s16 i=0; i<underground_level*1; i++)
2061                 {
2062                         if(myrand()%2 == 0)
2063                         {
2064                                 v3s16 cp(
2065                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2066                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2067                                         (myrand()%(MAP_BLOCKSIZE-2))+1
2068                                 );
2069
2070                                 MapNode n;
2071                                 n.d = CONTENT_MESE;
2072                                 
2073                                 //if(is_ground_content(block->getNode(cp).d))
2074                                 if(block->getNode(cp).d == CONTENT_STONE)
2075                                         if(myrand()%8 == 0)
2076                                                 block->setNode(cp, n);
2077
2078                                 for(u16 i=0; i<26; i++)
2079                                 {
2080                                         //if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
2081                                         if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
2082                                                 if(myrand()%8 == 0)
2083                                                         block->setNode(cp+g_26dirs[i], n);
2084                                 }
2085                         }
2086                 }
2087
2088                 /*
2089                         Add coal
2090                 */
2091                 u16 coal_amount = 30.0 * g_settings.getFloat("coal_amount");
2092                 u16 coal_rareness = 60 / coal_amount;
2093                 if(coal_rareness == 0)
2094                         coal_rareness = 1;
2095                 if(myrand()%coal_rareness == 0)
2096                 {
2097                         u16 a = myrand() % 16;
2098                         u16 amount = coal_amount * a*a*a / 1000;
2099                         for(s16 i=0; i<amount; i++)
2100                         {
2101                                 v3s16 cp(
2102                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2103                                         (myrand()%(MAP_BLOCKSIZE-2))+1,
2104                                         (myrand()%(MAP_BLOCKSIZE-2))+1
2105                                 );
2106
2107                                 MapNode n;
2108                                 n.d = CONTENT_COALSTONE;
2109
2110                                 //dstream<<"Adding coalstone"<<std::endl;
2111                                 
2112                                 //if(is_ground_content(block->getNode(cp).d))
2113                                 if(block->getNode(cp).d == CONTENT_STONE)
2114                                         if(myrand()%8 == 0)
2115                                                 block->setNode(cp, n);
2116
2117                                 for(u16 i=0; i<26; i++)
2118                                 {
2119                                         //if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
2120                                         if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
2121                                                 if(myrand()%8 == 0)
2122                                                         block->setNode(cp+g_26dirs[i], n);
2123                                 }
2124                         }
2125                 }
2126         }
2127         
2128         /*
2129                 Create a few rats in empty blocks underground
2130         */
2131         if(is_underground)
2132         {
2133                 //for(u16 i=0; i<2; i++)
2134                 {
2135                         v3s16 cp(
2136                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
2137                                 (myrand()%(MAP_BLOCKSIZE-2))+1,
2138                                 (myrand()%(MAP_BLOCKSIZE-2))+1
2139                         );
2140
2141                         // Check that the place is empty
2142                         //if(!is_ground_content(block->getNode(cp).d))
2143                         if(1)
2144                         {
2145                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
2146                                 block->addObject(obj);
2147                         }
2148                 }
2149         }
2150         
2151         /*
2152                 Add block to sector.
2153         */
2154         sector->insertBlock(block);
2155         
2156         /*
2157                 Sector object stuff
2158         */
2159                 
2160         // An y-wise container of changed blocks
2161         core::map<s16, MapBlock*> changed_blocks_sector;
2162
2163         /*
2164                 Check if any sector's objects can be placed now.
2165                 If so, place them.
2166         */
2167         core::map<v3s16, u8> *objects = sector->getObjects();
2168         core::list<v3s16> objects_to_remove;
2169         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
2170                         i.atEnd() == false; i++)
2171         {
2172                 v3s16 p = i.getNode()->getKey();
2173                 v2s16 p2d(p.X,p.Z);
2174                 u8 d = i.getNode()->getValue();
2175
2176                 //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
2177                 
2178                 try
2179                 {
2180
2181                 if(d == SECTOR_OBJECT_TEST)
2182                 {
2183                         if(sector->isValidArea(p + v3s16(0,0,0),
2184                                         p + v3s16(0,0,0), &changed_blocks_sector))
2185                         {
2186                                 MapNode n;
2187                                 n.d = CONTENT_TORCH;
2188                                 sector->setNode(p, n);
2189                                 objects_to_remove.push_back(p);
2190                         }
2191                 }
2192                 else if(d == SECTOR_OBJECT_TREE_1)
2193                 {
2194                         v3s16 p_min = p + v3s16(-1,0,-1);
2195                         v3s16 p_max = p + v3s16(1,4,1);
2196                         if(sector->isValidArea(p_min, p_max,
2197                                         &changed_blocks_sector))
2198                         {
2199                                 MapNode n;
2200                                 n.d = CONTENT_TREE;
2201                                 sector->setNode(p+v3s16(0,0,0), n);
2202                                 sector->setNode(p+v3s16(0,1,0), n);
2203                                 sector->setNode(p+v3s16(0,2,0), n);
2204                                 sector->setNode(p+v3s16(0,3,0), n);
2205
2206                                 n.d = CONTENT_LEAVES;
2207
2208                                 sector->setNode(p+v3s16(0,4,0), n);
2209                                 
2210                                 sector->setNode(p+v3s16(-1,4,0), n);
2211                                 sector->setNode(p+v3s16(1,4,0), n);
2212                                 sector->setNode(p+v3s16(0,4,-1), n);
2213                                 sector->setNode(p+v3s16(0,4,1), n);
2214                                 sector->setNode(p+v3s16(1,4,1), n);
2215                                 sector->setNode(p+v3s16(-1,4,1), n);
2216                                 sector->setNode(p+v3s16(-1,4,-1), n);
2217                                 sector->setNode(p+v3s16(1,4,-1), n);
2218
2219                                 sector->setNode(p+v3s16(-1,3,0), n);
2220                                 sector->setNode(p+v3s16(1,3,0), n);
2221                                 sector->setNode(p+v3s16(0,3,-1), n);
2222                                 sector->setNode(p+v3s16(0,3,1), n);
2223                                 sector->setNode(p+v3s16(1,3,1), n);
2224                                 sector->setNode(p+v3s16(-1,3,1), n);
2225                                 sector->setNode(p+v3s16(-1,3,-1), n);
2226                                 sector->setNode(p+v3s16(1,3,-1), n);
2227                                 
2228                                 objects_to_remove.push_back(p);
2229                                 
2230                                 // Lighting has to be recalculated for this one.
2231                                 sector->getBlocksInArea(p_min, p_max, 
2232                                                 lighting_invalidated_blocks);
2233                         }
2234                 }
2235                 else if(d == SECTOR_OBJECT_BUSH_1)
2236                 {
2237                         if(sector->isValidArea(p + v3s16(0,0,0),
2238                                         p + v3s16(0,0,0), &changed_blocks_sector))
2239                         {
2240                                 MapNode n;
2241                                 n.d = CONTENT_LEAVES;
2242                                 sector->setNode(p+v3s16(0,0,0), n);
2243                                 
2244                                 objects_to_remove.push_back(p);
2245                         }
2246                 }
2247                 else if(d == SECTOR_OBJECT_RAVINE)
2248                 {
2249                         s16 maxdepth = -20;
2250                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
2251                         v3s16 p_max = p + v3s16(6,6,6);
2252                         if(sector->isValidArea(p_min, p_max,
2253                                         &changed_blocks_sector))
2254                         {
2255                                 MapNode n;
2256                                 n.d = CONTENT_STONE;
2257                                 MapNode n2;
2258                                 n2.d = CONTENT_AIR;
2259                                 s16 depth = maxdepth + (myrand()%10);
2260                                 s16 z = 0;
2261                                 s16 minz = -6 - (-2);
2262                                 s16 maxz = 6 -1;
2263                                 for(s16 x=-6; x<=6; x++)
2264                                 {
2265                                         z += -1 + (myrand()%3);
2266                                         if(z < minz)
2267                                                 z = minz;
2268                                         if(z > maxz)
2269                                                 z = maxz;
2270                                         for(s16 y=depth+(myrand()%2); y<=6; y++)
2271                                         {
2272                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
2273                                                                 <<std::endl;*/
2274                                                 {
2275                                                         v3s16 p2 = p + v3s16(x,y,z-2);
2276                                                         if(is_ground_content(sector->getNode(p2).d)
2277                                                                         && !is_mineral(sector->getNode(p2).d))
2278                                                                 sector->setNode(p2, n);
2279                                                 }
2280                                                 {
2281                                                         v3s16 p2 = p + v3s16(x,y,z-1);
2282                                                         if(is_ground_content(sector->getNode(p2).d)
2283                                                                         && !is_mineral(sector->getNode(p2).d))
2284                                                                 sector->setNode(p2, n2);
2285                                                 }
2286                                                 {
2287                                                         v3s16 p2 = p + v3s16(x,y,z+0);
2288                                                         if(is_ground_content(sector->getNode(p2).d)
2289                                                                         && !is_mineral(sector->getNode(p2).d))
2290                                                                 sector->setNode(p2, n2);
2291                                                 }
2292                                                 {
2293                                                         v3s16 p2 = p + v3s16(x,y,z+1);
2294                                                         if(is_ground_content(sector->getNode(p2).d)
2295                                                                         && !is_mineral(sector->getNode(p2).d))
2296                                                                 sector->setNode(p2, n);
2297                                                 }
2298
2299                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
2300                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
2301                                         }
2302                                 }
2303                                 
2304                                 objects_to_remove.push_back(p);
2305                                 
2306                                 // Lighting has to be recalculated for this one.
2307                                 sector->getBlocksInArea(p_min, p_max, 
2308                                                 lighting_invalidated_blocks);
2309                         }
2310                 }
2311                 else
2312                 {
2313                         dstream<<"ServerMap::emergeBlock(): "
2314                                         "Invalid heightmap object"
2315                                         <<std::endl;
2316                 }
2317
2318                 }//try
2319                 catch(InvalidPositionException &e)
2320                 {
2321                         dstream<<"WARNING: "<<__FUNCTION_NAME
2322                                         <<": while inserting object "<<(int)d
2323                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
2324                                         <<" InvalidPositionException.what()="
2325                                         <<e.what()<<std::endl;
2326                         // This is not too fatal and seems to happen sometimes.
2327                         assert(0);
2328                 }
2329         }
2330
2331         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
2332                         i != objects_to_remove.end(); i++)
2333         {
2334                 objects->remove(*i);
2335         }
2336
2337         for(core::map<s16, MapBlock*>::Iterator
2338                         i = changed_blocks_sector.getIterator();
2339                         i.atEnd() == false; i++)
2340         {
2341                 MapBlock *block = i.getNode()->getValue();
2342
2343                 changed_blocks.insert(block->getPos(), block);
2344         }
2345
2346         return block;
2347 }
2348
2349 void ServerMap::createDir(std::string path)
2350 {
2351         if(fs::CreateDir(path) == false)
2352         {
2353                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2354                                 <<"\""<<path<<"\""<<std::endl;
2355                 throw BaseException("ServerMap failed to create directory");
2356         }
2357 }
2358
2359 std::string ServerMap::getSectorSubDir(v2s16 pos)
2360 {
2361         char cc[9];
2362         snprintf(cc, 9, "%.4x%.4x",
2363                         (unsigned int)pos.X&0xffff,
2364                         (unsigned int)pos.Y&0xffff);
2365
2366         return std::string(cc);
2367 }
2368
2369 std::string ServerMap::getSectorDir(v2s16 pos)
2370 {
2371         return m_savedir + "/sectors/" + getSectorSubDir(pos);
2372 }
2373
2374 v2s16 ServerMap::getSectorPos(std::string dirname)
2375 {
2376         if(dirname.size() != 8)
2377                 throw InvalidFilenameException("Invalid sector directory name");
2378         unsigned int x, y;
2379         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
2380         if(r != 2)
2381                 throw InvalidFilenameException("Invalid sector directory name");
2382         v2s16 pos((s16)x, (s16)y);
2383         return pos;
2384 }
2385
2386 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2387 {
2388         v2s16 p2d = getSectorPos(sectordir);
2389
2390         if(blockfile.size() != 4){
2391                 throw InvalidFilenameException("Invalid block filename");
2392         }
2393         unsigned int y;
2394         int r = sscanf(blockfile.c_str(), "%4x", &y);
2395         if(r != 1)
2396                 throw InvalidFilenameException("Invalid block filename");
2397         return v3s16(p2d.X, y, p2d.Y);
2398 }
2399
2400 // Debug helpers
2401 #define ENABLE_SECTOR_SAVING 1
2402 #define ENABLE_SECTOR_LOADING 1
2403 #define ENABLE_BLOCK_SAVING 1
2404 #define ENABLE_BLOCK_LOADING 1
2405
2406 void ServerMap::save(bool only_changed)
2407 {
2408         DSTACK(__FUNCTION_NAME);
2409         if(m_map_saving_enabled == false)
2410         {
2411                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2412                 return;
2413         }
2414         
2415         if(only_changed == false)
2416                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2417                                 <<std::endl;
2418         
2419         saveMasterHeightmap();
2420         
2421         u32 sector_meta_count = 0;
2422         u32 block_count = 0;
2423         
2424         { //sectorlock
2425         JMutexAutoLock lock(m_sector_mutex);
2426         
2427         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2428         for(; i.atEnd() == false; i++)
2429         {
2430                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2431                 assert(sector->getId() == MAPSECTOR_SERVER);
2432                 
2433                 if(ENABLE_SECTOR_SAVING)
2434                 {
2435                         if(sector->differs_from_disk || only_changed == false)
2436                         {
2437                                 saveSectorMeta(sector);
2438                                 sector_meta_count++;
2439                         }
2440                 }
2441                 if(ENABLE_BLOCK_SAVING)
2442                 {
2443                         core::list<MapBlock*> blocks;
2444                         sector->getBlocks(blocks);
2445                         core::list<MapBlock*>::Iterator j;
2446                         for(j=blocks.begin(); j!=blocks.end(); j++)
2447                         {
2448                                 MapBlock *block = *j;
2449                                 if(block->getChangedFlag() || only_changed == false)
2450                                 {
2451                                         saveBlock(block);
2452                                         block_count++;
2453                                 }
2454                         }
2455                 }
2456         }
2457
2458         }//sectorlock
2459         
2460         /*
2461                 Only print if something happened or saved whole map
2462         */
2463         if(only_changed == false || sector_meta_count != 0
2464                         || block_count != 0)
2465         {
2466                 dstream<<DTIME<<"ServerMap: Written: "
2467                                 <<sector_meta_count<<" sector metadata files, "
2468                                 <<block_count<<" block files"
2469                                 <<std::endl;
2470         }
2471 }
2472
2473 void ServerMap::loadAll()
2474 {
2475         DSTACK(__FUNCTION_NAME);
2476         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
2477
2478         loadMasterHeightmap();
2479
2480         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
2481
2482         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
2483         
2484         JMutexAutoLock lock(m_sector_mutex);
2485         
2486         s32 counter = 0;
2487         s32 printed_counter = -100000;
2488         s32 count = list.size();
2489
2490         std::vector<fs::DirListNode>::iterator i;
2491         for(i=list.begin(); i!=list.end(); i++)
2492         {
2493                 if(counter > printed_counter + 10)
2494                 {
2495                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
2496                         printed_counter = counter;
2497                 }
2498                 counter++;
2499
2500                 MapSector *sector = NULL;
2501
2502                 // We want directories
2503                 if(i->dir == false)
2504                         continue;
2505                 try{
2506                         sector = loadSectorMeta(i->name);
2507                 }
2508                 catch(InvalidFilenameException &e)
2509                 {
2510                         // This catches unknown crap in directory
2511                 }
2512                 
2513                 if(ENABLE_BLOCK_LOADING)
2514                 {
2515                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2516                                         (m_savedir+"/sectors/"+i->name);
2517                         std::vector<fs::DirListNode>::iterator i2;
2518                         for(i2=list2.begin(); i2!=list2.end(); i2++)
2519                         {
2520                                 // We want files
2521                                 if(i2->dir)
2522                                         continue;
2523                                 try{
2524                                         loadBlock(i->name, i2->name, sector);
2525                                 }
2526                                 catch(InvalidFilenameException &e)
2527                                 {
2528                                         // This catches unknown crap in directory
2529                                 }
2530                         }
2531                 }
2532         }
2533         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
2534 }
2535
2536 void ServerMap::saveMasterHeightmap()
2537 {
2538         DSTACK(__FUNCTION_NAME);
2539         createDir(m_savedir);
2540         
2541         std::string fullpath = m_savedir + "/master_heightmap";
2542         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2543         if(o.good() == false)
2544                 throw FileNotGoodException("Cannot open master heightmap");
2545         
2546         // Format used for writing
2547         u8 version = SER_FMT_VER_HIGHEST;
2548
2549 #if 0
2550         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
2551         /*
2552                 [0] u8 serialization version
2553                 [1] X master heightmap
2554         */
2555         u32 fullsize = 1 + hmdata.getSize();
2556         SharedBuffer<u8> data(fullsize);
2557
2558         data[0] = version;
2559         memcpy(&data[1], *hmdata, hmdata.getSize());
2560
2561         o.write((const char*)*data, fullsize);
2562 #endif
2563         
2564         m_heightmap->serialize(o, version);
2565 }
2566
2567 void ServerMap::loadMasterHeightmap()
2568 {
2569         DSTACK(__FUNCTION_NAME);
2570         std::string fullpath = m_savedir + "/master_heightmap";
2571         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2572         if(is.good() == false)
2573                 throw FileNotGoodException("Cannot open master heightmap");
2574         
2575         if(m_heightmap != NULL)
2576                 delete m_heightmap;
2577                 
2578         m_heightmap = UnlimitedHeightmap::deSerialize(is);
2579 }
2580
2581 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2582 {
2583         DSTACK(__FUNCTION_NAME);
2584         // Format used for writing
2585         u8 version = SER_FMT_VER_HIGHEST;
2586         // Get destination
2587         v2s16 pos = sector->getPos();
2588         createDir(m_savedir);
2589         createDir(m_savedir+"/sectors");
2590         std::string dir = getSectorDir(pos);
2591         createDir(dir);
2592         
2593         std::string fullpath = dir + "/heightmap";
2594         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2595         if(o.good() == false)
2596                 throw FileNotGoodException("Cannot open master heightmap");
2597
2598         sector->serialize(o, version);
2599         
2600         sector->differs_from_disk = false;
2601 }
2602
2603 MapSector* ServerMap::loadSectorMeta(std::string dirname)
2604 {
2605         DSTACK(__FUNCTION_NAME);
2606         // Get destination
2607         v2s16 p2d = getSectorPos(dirname);
2608         std::string dir = m_savedir + "/sectors/" + dirname;
2609         
2610         std::string fullpath = dir + "/heightmap";
2611         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2612         if(is.good() == false)
2613                 throw FileNotGoodException("Cannot open sector heightmap");
2614
2615         ServerMapSector *sector = ServerMapSector::deSerialize
2616                         (is, this, p2d, &m_hwrapper, m_sectors);
2617         
2618         sector->differs_from_disk = false;
2619
2620         return sector;
2621 }
2622
2623 bool ServerMap::loadSectorFull(v2s16 p2d)
2624 {
2625         DSTACK(__FUNCTION_NAME);
2626         std::string sectorsubdir = getSectorSubDir(p2d);
2627
2628         MapSector *sector = NULL;
2629
2630         JMutexAutoLock lock(m_sector_mutex);
2631
2632         try{
2633                 sector = loadSectorMeta(sectorsubdir);
2634         }
2635         catch(InvalidFilenameException &e)
2636         {
2637                 return false;
2638         }
2639         catch(FileNotGoodException &e)
2640         {
2641                 return false;
2642         }
2643         catch(std::exception &e)
2644         {
2645                 return false;
2646         }
2647
2648         if(ENABLE_BLOCK_LOADING)
2649         {
2650                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
2651                                 (m_savedir+"/sectors/"+sectorsubdir);
2652                 std::vector<fs::DirListNode>::iterator i2;
2653                 for(i2=list2.begin(); i2!=list2.end(); i2++)
2654                 {
2655                         // We want files
2656                         if(i2->dir)
2657                                 continue;
2658                         try{
2659                                 loadBlock(sectorsubdir, i2->name, sector);
2660                         }
2661                         catch(InvalidFilenameException &e)
2662                         {
2663                                 // This catches unknown crap in directory
2664                         }
2665                 }
2666         }
2667         return true;
2668 }
2669
2670 #if 0
2671 bool ServerMap::deFlushSector(v2s16 p2d)
2672 {
2673         DSTACK(__FUNCTION_NAME);
2674         // See if it already exists in memory
2675         try{
2676                 MapSector *sector = getSectorNoGenerate(p2d);
2677                 return true;
2678         }
2679         catch(InvalidPositionException &e)
2680         {
2681                 /*
2682                         Try to load the sector from disk.
2683                 */
2684                 if(loadSectorFull(p2d) == true)
2685                 {
2686                         return true;
2687                 }
2688         }
2689         return false;
2690 }
2691 #endif
2692
2693 void ServerMap::saveBlock(MapBlock *block)
2694 {
2695         DSTACK(__FUNCTION_NAME);
2696         /*
2697                 Dummy blocks are not written
2698         */
2699         if(block->isDummy())
2700         {
2701                 /*v3s16 p = block->getPos();
2702                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
2703                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2704                 return;
2705         }
2706
2707         // Format used for writing
2708         u8 version = SER_FMT_VER_HIGHEST;
2709         // Get destination
2710         v3s16 p3d = block->getPos();
2711         v2s16 p2d(p3d.X, p3d.Z);
2712         createDir(m_savedir);
2713         createDir(m_savedir+"/sectors");
2714         std::string dir = getSectorDir(p2d);
2715         createDir(dir);
2716         
2717         // Block file is map/sectors/xxxxxxxx/xxxx
2718         char cc[5];
2719         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
2720         std::string fullpath = dir + "/" + cc;
2721         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2722         if(o.good() == false)
2723                 throw FileNotGoodException("Cannot open block data");
2724
2725         /*
2726                 [0] u8 serialization version
2727                 [1] data
2728         */
2729         o.write((char*)&version, 1);
2730         
2731         block->serialize(o, version);
2732
2733         /*
2734                 Versions up from 9 have block objects.
2735         */
2736         if(version >= 9)
2737         {
2738                 block->serializeObjects(o, version);
2739         }
2740         
2741         // We just wrote it to the disk
2742         block->resetChangedFlag();
2743 }
2744
2745 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
2746 {
2747         DSTACK(__FUNCTION_NAME);
2748
2749         try{
2750
2751         // Block file is map/sectors/xxxxxxxx/xxxx
2752         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
2753         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2754         if(is.good() == false)
2755                 throw FileNotGoodException("Cannot open block file");
2756
2757         v3s16 p3d = getBlockPos(sectordir, blockfile);
2758         v2s16 p2d(p3d.X, p3d.Z);
2759         
2760         assert(sector->getPos() == p2d);
2761         
2762         u8 version = SER_FMT_VER_INVALID;
2763         is.read((char*)&version, 1);
2764
2765         /*u32 block_size = MapBlock::serializedLength(version);
2766         SharedBuffer<u8> data(block_size);
2767         is.read((char*)*data, block_size);*/
2768
2769         // This will always return a sector because we're the server
2770         //MapSector *sector = emergeSector(p2d);
2771
2772         MapBlock *block = NULL;
2773         bool created_new = false;
2774         try{
2775                 block = sector->getBlockNoCreate(p3d.Y);
2776         }
2777         catch(InvalidPositionException &e)
2778         {
2779                 block = sector->createBlankBlockNoInsert(p3d.Y);
2780                 created_new = true;
2781         }
2782         
2783         // deserialize block data
2784         block->deSerialize(is, version);
2785         
2786         /*
2787                 Versions up from 9 have block objects.
2788         */
2789         if(version >= 9)
2790         {
2791                 block->updateObjects(is, version, NULL, 0);
2792         }
2793
2794         if(created_new)
2795                 sector->insertBlock(block);
2796         
2797         /*
2798                 Convert old formats to new and save
2799         */
2800
2801         // Save old format blocks in new format
2802         if(version < SER_FMT_VER_HIGHEST)
2803         {
2804                 saveBlock(block);
2805         }
2806         
2807         // We just loaded it from the disk, so it's up-to-date.
2808         block->resetChangedFlag();
2809
2810         }
2811         catch(SerializationError &e)
2812         {
2813                 dstream<<"WARNING: Invalid block data on disk "
2814                                 "(SerializationError). Ignoring."
2815                                 <<std::endl;
2816         }
2817 }
2818
2819 // Gets from master heightmap
2820 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
2821 {
2822         assert(m_heightmap != NULL);
2823         /*
2824                 Corner definition:
2825                 v2s16(0,0),
2826                 v2s16(1,0),
2827                 v2s16(1,1),
2828                 v2s16(0,1),
2829         */
2830         corners[0] = m_heightmap->getGroundHeight
2831                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
2832         corners[1] = m_heightmap->getGroundHeight
2833                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
2834         corners[2] = m_heightmap->getGroundHeight
2835                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
2836         corners[3] = m_heightmap->getGroundHeight
2837                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
2838 }
2839
2840 void ServerMap::PrintInfo(std::ostream &out)
2841 {
2842         out<<"ServerMap: ";
2843 }
2844
2845 #ifndef SERVER
2846
2847 /*
2848         ClientMap
2849 */
2850
2851 ClientMap::ClientMap(
2852                 Client *client,
2853                 MapDrawControl &control,
2854                 scene::ISceneNode* parent,
2855                 scene::ISceneManager* mgr,
2856                 s32 id
2857 ):
2858         Map(dout_client),
2859         scene::ISceneNode(parent, mgr, id),
2860         m_client(client),
2861         mesh(NULL),
2862         m_control(control)
2863 {
2864         mesh_mutex.Init();
2865
2866         /*m_box = core::aabbox3d<f32>(0,0,0,
2867                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
2868         /*m_box = core::aabbox3d<f32>(0,0,0,
2869                         map->getSizeNodes().X * BS,
2870                         map->getSizeNodes().Y * BS,
2871                         map->getSizeNodes().Z * BS);*/
2872         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
2873                         BS*1000000,BS*1000000,BS*1000000);
2874         
2875         //setPosition(v3f(BS,BS,BS));
2876 }
2877
2878 ClientMap::~ClientMap()
2879 {
2880         JMutexAutoLock lock(mesh_mutex);
2881         
2882         if(mesh != NULL)
2883         {
2884                 mesh->drop();
2885                 mesh = NULL;
2886         }
2887 }
2888
2889 MapSector * ClientMap::emergeSector(v2s16 p2d)
2890 {
2891         DSTACK(__FUNCTION_NAME);
2892         // Check that it doesn't exist already
2893         try{
2894                 return getSectorNoGenerate(p2d);
2895         }
2896         catch(InvalidPositionException &e)
2897         {
2898         }
2899         
2900         // Create a sector with no heightmaps
2901         ClientMapSector *sector = new ClientMapSector(this, p2d);
2902         
2903         {
2904                 JMutexAutoLock lock(m_sector_mutex);
2905                 m_sectors.insert(p2d, sector);
2906         }
2907         
2908         return sector;
2909 }
2910
2911 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
2912 {
2913         DSTACK(__FUNCTION_NAME);
2914         ClientMapSector *sector = NULL;
2915
2916         JMutexAutoLock lock(m_sector_mutex);
2917         
2918         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
2919
2920         if(n != NULL)
2921         {
2922                 sector = (ClientMapSector*)n->getValue();
2923                 assert(sector->getId() == MAPSECTOR_CLIENT);
2924         }
2925         else
2926         {
2927                 sector = new ClientMapSector(this, p2d);
2928                 {
2929                         JMutexAutoLock lock(m_sector_mutex);
2930                         m_sectors.insert(p2d, sector);
2931                 }
2932         }
2933
2934         sector->deSerialize(is);
2935 }
2936
2937 void ClientMap::OnRegisterSceneNode()
2938 {
2939         if(IsVisible)
2940         {
2941                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
2942                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
2943         }
2944
2945         ISceneNode::OnRegisterSceneNode();
2946 }
2947
2948 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
2949 {
2950         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
2951         DSTACK(__FUNCTION_NAME);
2952
2953         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
2954
2955         /*
2956                 Get time for measuring timeout.
2957                 
2958                 Measuring time is very useful for long delays when the
2959                 machine is swapping a lot.
2960         */
2961         int time1 = time(0);
2962
2963         u32 daynight_ratio = m_client->getDayNightRatio();
2964
2965         m_camera_mutex.Lock();
2966         v3f camera_position = m_camera_position;
2967         v3f camera_direction = m_camera_direction;
2968         m_camera_mutex.Unlock();
2969
2970         /*
2971                 Get all blocks and draw all visible ones
2972         */
2973
2974         v3s16 cam_pos_nodes(
2975                         camera_position.X / BS,
2976                         camera_position.Y / BS,
2977                         camera_position.Z / BS);
2978
2979         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
2980
2981         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
2982         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
2983
2984         // Take a fair amount as we will be dropping more out later
2985         v3s16 p_blocks_min(
2986                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
2987                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
2988                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
2989         v3s16 p_blocks_max(
2990                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
2991                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
2992                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
2993         
2994         u32 vertex_count = 0;
2995         
2996         // For limiting number of mesh updates per frame
2997         u32 mesh_update_count = 0;
2998         
2999         u32 blocks_would_have_drawn = 0;
3000         u32 blocks_drawn = 0;
3001
3002         //NOTE: The sectors map should be locked but we're not doing it
3003         // because it'd cause too much delays
3004
3005         int timecheck_counter = 0;
3006         core::map<v2s16, MapSector*>::Iterator si;
3007         si = m_sectors.getIterator();
3008         for(; si.atEnd() == false; si++)
3009         {
3010                 {
3011                         timecheck_counter++;
3012                         if(timecheck_counter > 50)
3013                         {
3014                                 int time2 = time(0);
3015                                 if(time2 > time1 + 4)
3016                                 {
3017                                         dstream<<"ClientMap::renderMap(): "
3018                                                 "Rendering takes ages, returning."
3019                                                 <<std::endl;
3020                                         return;
3021                                 }
3022                         }
3023                 }
3024
3025                 MapSector *sector = si.getNode()->getValue();
3026                 v2s16 sp = sector->getPos();
3027                 
3028                 if(m_control.range_all == false)
3029                 {
3030                         if(sp.X < p_blocks_min.X
3031                         || sp.X > p_blocks_max.X
3032                         || sp.Y < p_blocks_min.Z
3033                         || sp.Y > p_blocks_max.Z)
3034                                 continue;
3035                 }
3036
3037                 core::list< MapBlock * > sectorblocks;
3038                 sector->getBlocks(sectorblocks);
3039                 
3040                 /*
3041                         Draw blocks
3042                 */
3043
3044                 core::list< MapBlock * >::Iterator i;
3045                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3046                 {
3047                         MapBlock *block = *i;
3048
3049                         /*
3050                                 Compare block position to camera position, skip
3051                                 if not seen on display
3052                         */
3053                         
3054                         v3s16 blockpos_nodes = block->getPosRelative();
3055                         
3056                         // Block center position
3057                         v3f blockpos(
3058                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
3059                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
3060                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
3061                         );
3062
3063                         // Block position relative to camera
3064                         v3f blockpos_relative = blockpos - camera_position;
3065
3066                         // Distance in camera direction (+=front, -=back)
3067                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
3068
3069                         // Total distance
3070                         f32 d = blockpos_relative.getLength();
3071                         
3072                         if(m_control.range_all == false)
3073                         {
3074                                 // If block is far away, don't draw it
3075                                 if(d > m_control.wanted_range * BS)
3076                                 // This is nicer when fog is used
3077                                 //if((dforward+d)/2 > m_control.wanted_range * BS)
3078                                         continue;
3079                         }
3080                         
3081                         // Maximum radius of a block
3082                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
3083                         
3084                         // If block is (nearly) touching the camera, don't
3085                         // bother validating further (that is, render it anyway)
3086                         if(d > block_max_radius * 1.5)
3087                         {
3088                                 // Cosine of the angle between the camera direction
3089                                 // and the block direction (camera_direction is an unit vector)
3090                                 f32 cosangle = dforward / d;
3091                                 
3092                                 // Compensate for the size of the block
3093                                 // (as the block has to be shown even if it's a bit off FOV)
3094                                 // This is an estimate.
3095                                 cosangle += block_max_radius / dforward;
3096
3097                                 // If block is not in the field of view, skip it
3098                                 //if(cosangle < cos(FOV_ANGLE/2))
3099                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
3100                                         continue;
3101                         }
3102                         
3103                         /*
3104                                 Draw the faces of the block
3105                         */
3106 #if 1
3107                         bool mesh_expired = false;
3108                         
3109                         {
3110                                 JMutexAutoLock lock(block->mesh_mutex);
3111
3112                                 mesh_expired = block->getMeshExpired();
3113
3114                                 // Mesh has not been expired and there is no mesh:
3115                                 // block has no content
3116                                 if(block->mesh == NULL && mesh_expired == false)
3117                                         continue;
3118                         }
3119
3120                         f32 faraway = BS*50;
3121                         //f32 faraway = m_control.wanted_range * BS;
3122                         
3123                         /*
3124                                 This has to be done with the mesh_mutex unlocked
3125                         */
3126                         if(mesh_expired && mesh_update_count < 6
3127                                         && (d < faraway || mesh_update_count < 3))
3128                         //if(mesh_expired && mesh_update_count < 4)
3129                         {
3130                                 mesh_update_count++;
3131
3132                                 // Mesh has been expired: generate new mesh
3133                                 //block->updateMeshes(daynight_i);
3134                                 block->updateMesh(daynight_ratio);
3135
3136                                 mesh_expired = false;
3137                         }
3138                         
3139                         /*
3140                                 Don't draw an expired mesh that is far away
3141                         */
3142                         /*if(mesh_expired && d >= faraway)
3143                         //if(mesh_expired)
3144                         {
3145                                 // Instead, delete it
3146                                 JMutexAutoLock lock(block->mesh_mutex);
3147                                 if(block->mesh)
3148                                 {
3149                                         block->mesh->drop();
3150                                         block->mesh = NULL;
3151                                 }
3152                                 // And continue to next block
3153                                 continue;
3154                         }*/
3155 #endif
3156                         {
3157                                 JMutexAutoLock lock(block->mesh_mutex);
3158
3159                                 scene::SMesh *mesh = block->mesh;
3160
3161                                 if(mesh == NULL)
3162                                         continue;
3163                                 
3164                                 blocks_would_have_drawn++;
3165                                 if(blocks_drawn >= m_control.wanted_max_blocks
3166                                                 && m_control.range_all == false
3167                                                 && d > m_control.wanted_min_range * BS)
3168                                         continue;
3169                                 blocks_drawn++;
3170
3171                                 u32 c = mesh->getMeshBufferCount();
3172
3173                                 for(u32 i=0; i<c; i++)
3174                                 {
3175                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3176                                         const video::SMaterial& material = buf->getMaterial();
3177                                         video::IMaterialRenderer* rnd =
3178                                                         driver->getMaterialRenderer(material.MaterialType);
3179                                         bool transparent = (rnd && rnd->isTransparent());
3180                                         // Render transparent on transparent pass and likewise.
3181                                         if(transparent == is_transparent_pass)
3182                                         {
3183                                                 driver->setMaterial(buf->getMaterial());
3184                                                 driver->drawMeshBuffer(buf);
3185                                                 vertex_count += buf->getVertexCount();
3186                                         }
3187                                 }
3188                         }
3189                 } // foreach sectorblocks
3190         }
3191         
3192         m_control.blocks_drawn = blocks_drawn;
3193         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
3194
3195         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3196                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3197 }
3198
3199 v3s16 ClientMap::setTempMod(v3s16 p, NodeMod mod)
3200 {
3201         /*
3202                 Add it to all blocks touching it
3203         */
3204         v3s16 dirs[7] = {
3205                 v3s16(0,0,0), // this
3206                 v3s16(0,0,1), // back
3207                 v3s16(0,1,0), // top
3208                 v3s16(1,0,0), // right
3209                 v3s16(0,0,-1), // front
3210                 v3s16(0,-1,0), // bottom
3211                 v3s16(-1,0,0), // left
3212         };
3213         for(u16 i=0; i<7; i++)
3214         {
3215                 v3s16 p2 = p + dirs[i];
3216                 // Block position of neighbor (or requested) node
3217                 v3s16 blockpos = getNodeBlockPos(p2);
3218                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3219                 if(blockref == NULL)
3220                         continue;
3221                 // Relative position of requested node
3222                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3223                 blockref->setTempMod(relpos, mod);
3224         }
3225         return getNodeBlockPos(p);
3226 }
3227 v3s16 ClientMap::clearTempMod(v3s16 p)
3228 {
3229         v3s16 dirs[7] = {
3230                 v3s16(0,0,0), // this
3231                 v3s16(0,0,1), // back
3232                 v3s16(0,1,0), // top
3233                 v3s16(1,0,0), // right
3234                 v3s16(0,0,-1), // front
3235                 v3s16(0,-1,0), // bottom
3236                 v3s16(-1,0,0), // left
3237         };
3238         for(u16 i=0; i<7; i++)
3239         {
3240                 v3s16 p2 = p + dirs[i];
3241                 // Block position of neighbor (or requested) node
3242                 v3s16 blockpos = getNodeBlockPos(p2);
3243                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3244                 if(blockref == NULL)
3245                         continue;
3246                 // Relative position of requested node
3247                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3248                 blockref->clearTempMod(relpos);
3249         }
3250         return getNodeBlockPos(p);
3251 }
3252
3253 void ClientMap::PrintInfo(std::ostream &out)
3254 {
3255         out<<"ClientMap: ";
3256 }
3257
3258 #endif // !SERVER
3259
3260 /*
3261         MapVoxelManipulator
3262 */
3263
3264 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3265 {
3266         m_map = map;
3267 }
3268
3269 MapVoxelManipulator::~MapVoxelManipulator()
3270 {
3271         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3272                         <<std::endl;*/
3273 }
3274
3275 #if 1
3276 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3277 {
3278         TimeTaker timer1("emerge", &emerge_time);
3279
3280         // Units of these are MapBlocks
3281         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3282         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3283
3284         VoxelArea block_area_nodes
3285                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3286
3287         addArea(block_area_nodes);
3288
3289         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3290         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3291         for(s32 x=p_min.X; x<=p_max.X; x++)
3292         {
3293                 v3s16 p(x,y,z);
3294                 core::map<v3s16, bool>::Node *n;
3295                 n = m_loaded_blocks.find(p);
3296                 if(n != NULL)
3297                         continue;
3298                 
3299                 bool block_data_inexistent = false;
3300                 try
3301                 {
3302                         TimeTaker timer1("emerge load", &emerge_load_time);
3303
3304                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3305                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3306                                         <<" wanted area: ";
3307                         a.print(dstream);
3308                         dstream<<std::endl;*/
3309                         
3310                         MapBlock *block = m_map->getBlockNoCreate(p);
3311                         if(block->isDummy())
3312                                 block_data_inexistent = true;
3313                         else
3314                                 block->copyTo(*this);
3315                 }
3316                 catch(InvalidPositionException &e)
3317                 {
3318                         block_data_inexistent = true;
3319                 }
3320
3321                 if(block_data_inexistent)
3322                 {
3323                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3324                         // Fill with VOXELFLAG_INEXISTENT
3325                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3326                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3327                         {
3328                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3329                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3330                         }
3331                 }
3332
3333                 m_loaded_blocks.insert(p, true);
3334         }
3335
3336         //dstream<<"emerge done"<<std::endl;
3337 }
3338 #endif
3339
3340 #if 0
3341 void MapVoxelManipulator::emerge(VoxelArea a)
3342 {
3343         TimeTaker timer1("emerge", &emerge_time);
3344         
3345         v3s16 size = a.getExtent();
3346         
3347         VoxelArea padded = a;
3348         padded.pad(m_area.getExtent() / 4);
3349         addArea(padded);
3350
3351         for(s16 z=0; z<size.Z; z++)
3352         for(s16 y=0; y<size.Y; y++)
3353         for(s16 x=0; x<size.X; x++)
3354         {
3355                 v3s16 p(x,y,z);
3356                 s32 i = m_area.index(a.MinEdge + p);
3357                 // Don't touch nodes that have already been loaded
3358                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
3359                         continue;
3360                 try
3361                 {
3362                         TimeTaker timer1("emerge load", &emerge_load_time);
3363                         MapNode n = m_map->getNode(a.MinEdge + p);
3364                         m_data[i] = n;
3365                         m_flags[i] = 0;
3366                 }
3367                 catch(InvalidPositionException &e)
3368                 {
3369                         m_flags[i] = VOXELFLAG_INEXISTENT;
3370                 }
3371         }
3372 }
3373 #endif
3374
3375
3376 /*
3377         TODO: Add an option to only update eg. water and air nodes.
3378               This will make it interfere less with important stuff if
3379                   run on background.
3380 */
3381 void MapVoxelManipulator::blitBack
3382                 (core::map<v3s16, MapBlock*> & modified_blocks)
3383 {
3384         if(m_area.getExtent() == v3s16(0,0,0))
3385                 return;
3386         
3387         //TimeTaker timer1("blitBack");
3388         
3389         /*
3390                 Initialize block cache
3391         */
3392         v3s16 blockpos_last;
3393         MapBlock *block = NULL;
3394         bool block_checked_in_modified = false;
3395
3396         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3397         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3398         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3399         {
3400                 v3s16 p(x,y,z);
3401
3402                 u8 f = m_flags[m_area.index(p)];
3403                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3404                         continue;
3405
3406                 MapNode &n = m_data[m_area.index(p)];
3407                         
3408                 v3s16 blockpos = getNodeBlockPos(p);
3409                 
3410                 try
3411                 {
3412                         // Get block
3413                         if(block == NULL || blockpos != blockpos_last){
3414                                 block = m_map->getBlockNoCreate(blockpos);
3415                                 blockpos_last = blockpos;
3416                                 block_checked_in_modified = false;
3417                         }
3418                         
3419                         // Calculate relative position in block
3420                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3421
3422                         // Don't continue if nothing has changed here
3423                         if(block->getNode(relpos) == n)
3424                                 continue;
3425
3426                         //m_map->setNode(m_area.MinEdge + p, n);
3427                         block->setNode(relpos, n);
3428                         
3429                         /*
3430                                 Make sure block is in modified_blocks
3431                         */
3432                         if(block_checked_in_modified == false)
3433                         {
3434                                 modified_blocks[blockpos] = block;
3435                                 block_checked_in_modified = true;
3436                         }
3437                 }
3438                 catch(InvalidPositionException &e)
3439                 {
3440                 }
3441         }
3442 }
3443
3444 //END