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