]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
d5a61d408f0c49d4101d4b774ecb96168b5bc4ee
[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                 JMutex &range_mutex,
2893                 float &viewing_range_nodes,
2894                 bool &viewing_range_all,
2895                 scene::ISceneNode* parent,
2896                 scene::ISceneManager* mgr,
2897                 s32 id
2898 ):
2899         Map(dout_client),
2900         scene::ISceneNode(parent, mgr, id),
2901         m_client(client),
2902         mesh(NULL),
2903         m_range_mutex(range_mutex),
2904         m_viewing_range_nodes(viewing_range_nodes),
2905         m_viewing_range_all(viewing_range_all)
2906 {
2907         mesh_mutex.Init();
2908
2909         /*m_box = core::aabbox3d<f32>(0,0,0,
2910                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
2911         /*m_box = core::aabbox3d<f32>(0,0,0,
2912                         map->getSizeNodes().X * BS,
2913                         map->getSizeNodes().Y * BS,
2914                         map->getSizeNodes().Z * BS);*/
2915         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
2916                         BS*1000000,BS*1000000,BS*1000000);
2917         
2918         //setPosition(v3f(BS,BS,BS));
2919 }
2920
2921 ClientMap::~ClientMap()
2922 {
2923         JMutexAutoLock lock(mesh_mutex);
2924         
2925         if(mesh != NULL)
2926         {
2927                 mesh->drop();
2928                 mesh = NULL;
2929         }
2930 }
2931
2932 MapSector * ClientMap::emergeSector(v2s16 p2d)
2933 {
2934         DSTACK(__FUNCTION_NAME);
2935         // Check that it doesn't exist already
2936         try{
2937                 return getSectorNoGenerate(p2d);
2938         }
2939         catch(InvalidPositionException &e)
2940         {
2941         }
2942         
2943         // Create a sector with no heightmaps
2944         ClientMapSector *sector = new ClientMapSector(this, p2d);
2945         
2946         {
2947                 JMutexAutoLock lock(m_sector_mutex);
2948                 m_sectors.insert(p2d, sector);
2949         }
2950         
2951         return sector;
2952 }
2953
2954 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
2955 {
2956         DSTACK(__FUNCTION_NAME);
2957         ClientMapSector *sector = NULL;
2958
2959         JMutexAutoLock lock(m_sector_mutex);
2960         
2961         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
2962
2963         if(n != NULL)
2964         {
2965                 sector = (ClientMapSector*)n->getValue();
2966                 assert(sector->getId() == MAPSECTOR_CLIENT);
2967         }
2968         else
2969         {
2970                 sector = new ClientMapSector(this, p2d);
2971                 {
2972                         JMutexAutoLock lock(m_sector_mutex);
2973                         m_sectors.insert(p2d, sector);
2974                 }
2975         }
2976
2977         sector->deSerialize(is);
2978 }
2979
2980 void ClientMap::OnRegisterSceneNode()
2981 {
2982         if(IsVisible)
2983         {
2984                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
2985                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
2986         }
2987
2988         ISceneNode::OnRegisterSceneNode();
2989 }
2990
2991 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
2992 {
2993         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
2994         DSTACK(__FUNCTION_NAME);
2995
2996         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
2997
2998         /*
2999                 Get time for measuring timeout.
3000                 
3001                 Measuring time is very useful for long delays when the
3002                 machine is swapping a lot.
3003         */
3004         int time1 = time(0);
3005
3006         //s32 daynight_i = m_client->getDayNightIndex();
3007         u32 daynight_ratio = m_client->getDayNightRatio();
3008
3009         /*
3010                 Collect all blocks that are in the view range
3011
3012                 Should not optimize more here as we want to auto-update
3013                 all changed nodes in viewing range at the next step.
3014         */
3015
3016         float viewing_range_nodes;
3017         bool viewing_range_all;
3018         {
3019                 JMutexAutoLock lock(m_range_mutex);
3020                 viewing_range_nodes = m_viewing_range_nodes;
3021                 viewing_range_all = m_viewing_range_all;
3022         }
3023
3024         m_camera_mutex.Lock();
3025         v3f camera_position = m_camera_position;
3026         v3f camera_direction = m_camera_direction;
3027         m_camera_mutex.Unlock();
3028
3029         /*
3030                 Get all blocks and draw all visible ones
3031         */
3032
3033         v3s16 cam_pos_nodes(
3034                         camera_position.X / BS,
3035                         camera_position.Y / BS,
3036                         camera_position.Z / BS);
3037
3038         v3s16 box_nodes_d = viewing_range_nodes * v3s16(1,1,1);
3039
3040         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3041         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3042
3043         // Take a fair amount as we will be dropping more out later
3044         v3s16 p_blocks_min(
3045                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
3046                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
3047                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
3048         v3s16 p_blocks_max(
3049                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3050                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3051                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3052         
3053         u32 vertex_count = 0;
3054         
3055         // For limiting number of mesh updates per frame
3056         u32 mesh_update_count = 0;
3057
3058         //NOTE: The sectors map should be locked but we're not doing it
3059         // because it'd cause too much delays
3060
3061         int timecheck_counter = 0;
3062
3063         core::map<v2s16, MapSector*>::Iterator si;
3064         si = m_sectors.getIterator();
3065         for(; si.atEnd() == false; si++)
3066         {
3067                 {
3068                         timecheck_counter++;
3069                         if(timecheck_counter > 50)
3070                         {
3071                                 int time2 = time(0);
3072                                 if(time2 > time1 + 4)
3073                                 {
3074                                         dstream<<"ClientMap::renderMap(): "
3075                                                 "Rendering takes ages, returning."
3076                                                 <<std::endl;
3077                                         return;
3078                                 }
3079                         }
3080                 }
3081
3082                 MapSector *sector = si.getNode()->getValue();
3083                 v2s16 sp = sector->getPos();
3084                 
3085                 if(viewing_range_all == false)
3086                 {
3087                         if(sp.X < p_blocks_min.X
3088                         || sp.X > p_blocks_max.X
3089                         || sp.Y < p_blocks_min.Z
3090                         || sp.Y > p_blocks_max.Z)
3091                                 continue;
3092                 }
3093
3094                 core::list< MapBlock * > sectorblocks;
3095                 sector->getBlocks(sectorblocks);
3096                 
3097                 /*
3098                         Draw blocks
3099                 */
3100
3101                 core::list< MapBlock * >::Iterator i;
3102                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3103                 {
3104                         MapBlock *block = *i;
3105
3106                         /*
3107                                 Compare block position to camera position, skip
3108                                 if not seen on display
3109                         */
3110                         
3111                         v3s16 blockpos_nodes = block->getPosRelative();
3112                         
3113                         // Block center position
3114                         v3f blockpos(
3115                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
3116                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
3117                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
3118                         );
3119
3120                         // Block position relative to camera
3121                         v3f blockpos_relative = blockpos - camera_position;
3122
3123                         // Distance in camera direction (+=front, -=back)
3124                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
3125
3126                         // Total distance
3127                         f32 d = blockpos_relative.getLength();
3128                         
3129                         if(viewing_range_all == false)
3130                         {
3131                                 // If block is far away, don't draw it
3132                                 if(d > viewing_range_nodes * BS)
3133                                 // This is nicer when fog is used
3134                                 //if((dforward+d)/2 > viewing_range_nodes * BS)
3135                                         continue;
3136                         }
3137                         
3138                         // Maximum radius of a block
3139                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
3140                         
3141                         // If block is (nearly) touching the camera, don't
3142                         // bother validating further (that is, render it anyway)
3143                         if(d > block_max_radius * 1.5)
3144                         {
3145                                 // Cosine of the angle between the camera direction
3146                                 // and the block direction (camera_direction is an unit vector)
3147                                 f32 cosangle = dforward / d;
3148                                 
3149                                 // Compensate for the size of the block
3150                                 // (as the block has to be shown even if it's a bit off FOV)
3151                                 // This is an estimate.
3152                                 cosangle += block_max_radius / dforward;
3153
3154                                 // If block is not in the field of view, skip it
3155                                 //if(cosangle < cos(FOV_ANGLE/2))
3156                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
3157                                         continue;
3158                         }
3159                         
3160                         /*
3161                                 Draw the faces of the block
3162                         */
3163 #if 1
3164                         bool mesh_expired = false;
3165                         
3166                         {
3167                                 JMutexAutoLock lock(block->mesh_mutex);
3168
3169                                 mesh_expired = block->getMeshExpired();
3170
3171                                 // Mesh has not been expired and there is no mesh:
3172                                 // block has no content
3173                                 if(block->mesh == NULL && mesh_expired == false)
3174                                         continue;
3175                         }
3176
3177                         f32 faraway = BS*50;
3178                         //f32 faraway = viewing_range_nodes * BS;
3179                         
3180                         /*
3181                                 This has to be done with the mesh_mutex unlocked
3182                         */
3183                         if(mesh_expired && mesh_update_count < 6
3184                                         && (d < faraway || mesh_update_count < 3))
3185                         //if(mesh_expired && mesh_update_count < 4)
3186                         {
3187                                 mesh_update_count++;
3188
3189                                 // Mesh has been expired: generate new mesh
3190                                 //block->updateMeshes(daynight_i);
3191                                 block->updateMesh(daynight_ratio);
3192
3193                                 mesh_expired = false;
3194                         }
3195                         
3196                         /*
3197                                 Don't draw an expired mesh that is far away
3198                         */
3199                         /*if(mesh_expired && d >= faraway)
3200                         //if(mesh_expired)
3201                         {
3202                                 // Instead, delete it
3203                                 JMutexAutoLock lock(block->mesh_mutex);
3204                                 if(block->mesh)
3205                                 {
3206                                         block->mesh->drop();
3207                                         block->mesh = NULL;
3208                                 }
3209                                 // And continue to next block
3210                                 continue;
3211                         }*/
3212 #endif
3213                         {
3214                                 JMutexAutoLock lock(block->mesh_mutex);
3215
3216                                 scene::SMesh *mesh = block->mesh;
3217
3218                                 if(mesh == NULL)
3219                                         continue;
3220
3221                                 u32 c = mesh->getMeshBufferCount();
3222
3223                                 for(u32 i=0; i<c; i++)
3224                                 {
3225                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3226                                         const video::SMaterial& material = buf->getMaterial();
3227                                         video::IMaterialRenderer* rnd =
3228                                                         driver->getMaterialRenderer(material.MaterialType);
3229                                         bool transparent = (rnd && rnd->isTransparent());
3230                                         // Render transparent on transparent pass and likewise.
3231                                         if(transparent == is_transparent_pass)
3232                                         {
3233                                                 driver->setMaterial(buf->getMaterial());
3234                                                 driver->drawMeshBuffer(buf);
3235                                                 vertex_count += buf->getVertexCount();
3236                                         }
3237                                 }
3238                         }
3239                 } // foreach sectorblocks
3240         }
3241
3242         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3243                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3244 }
3245
3246 v3s16 ClientMap::setTempMod(v3s16 p, NodeMod mod)
3247 {
3248         /*
3249                 Add it to all blocks touching it
3250         */
3251         v3s16 dirs[7] = {
3252                 v3s16(0,0,0), // this
3253                 v3s16(0,0,1), // back
3254                 v3s16(0,1,0), // top
3255                 v3s16(1,0,0), // right
3256                 v3s16(0,0,-1), // front
3257                 v3s16(0,-1,0), // bottom
3258                 v3s16(-1,0,0), // left
3259         };
3260         for(u16 i=0; i<7; i++)
3261         {
3262                 v3s16 p2 = p + dirs[i];
3263                 // Block position of neighbor (or requested) node
3264                 v3s16 blockpos = getNodeBlockPos(p2);
3265                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3266                 if(blockref == NULL)
3267                         continue;
3268                 // Relative position of requested node
3269                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3270                 blockref->setTempMod(relpos, mod);
3271         }
3272         return getNodeBlockPos(p);
3273 }
3274 v3s16 ClientMap::clearTempMod(v3s16 p)
3275 {
3276         v3s16 dirs[7] = {
3277                 v3s16(0,0,0), // this
3278                 v3s16(0,0,1), // back
3279                 v3s16(0,1,0), // top
3280                 v3s16(1,0,0), // right
3281                 v3s16(0,0,-1), // front
3282                 v3s16(0,-1,0), // bottom
3283                 v3s16(-1,0,0), // left
3284         };
3285         for(u16 i=0; i<7; i++)
3286         {
3287                 v3s16 p2 = p + dirs[i];
3288                 // Block position of neighbor (or requested) node
3289                 v3s16 blockpos = getNodeBlockPos(p2);
3290                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3291                 if(blockref == NULL)
3292                         continue;
3293                 // Relative position of requested node
3294                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3295                 blockref->clearTempMod(relpos);
3296         }
3297         return getNodeBlockPos(p);
3298 }
3299
3300 void ClientMap::PrintInfo(std::ostream &out)
3301 {
3302         out<<"ClientMap: ";
3303 }
3304
3305 #endif // !SERVER
3306
3307 /*
3308         MapVoxelManipulator
3309 */
3310
3311 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3312 {
3313         m_map = map;
3314 }
3315
3316 MapVoxelManipulator::~MapVoxelManipulator()
3317 {
3318         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3319                         <<std::endl;*/
3320 }
3321
3322 #if 1
3323 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3324 {
3325         TimeTaker timer1("emerge", &emerge_time);
3326
3327         // Units of these are MapBlocks
3328         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3329         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3330
3331         VoxelArea block_area_nodes
3332                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3333
3334         addArea(block_area_nodes);
3335
3336         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3337         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3338         for(s32 x=p_min.X; x<=p_max.X; x++)
3339         {
3340                 v3s16 p(x,y,z);
3341                 core::map<v3s16, bool>::Node *n;
3342                 n = m_loaded_blocks.find(p);
3343                 if(n != NULL)
3344                         continue;
3345                 
3346                 bool block_data_inexistent = false;
3347                 try
3348                 {
3349                         TimeTaker timer1("emerge load", &emerge_load_time);
3350
3351                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3352                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3353                                         <<" wanted area: ";
3354                         a.print(dstream);
3355                         dstream<<std::endl;*/
3356                         
3357                         MapBlock *block = m_map->getBlockNoCreate(p);
3358                         if(block->isDummy())
3359                                 block_data_inexistent = true;
3360                         else
3361                                 block->copyTo(*this);
3362                 }
3363                 catch(InvalidPositionException &e)
3364                 {
3365                         block_data_inexistent = true;
3366                 }
3367
3368                 if(block_data_inexistent)
3369                 {
3370                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3371                         // Fill with VOXELFLAG_INEXISTENT
3372                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3373                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3374                         {
3375                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3376                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3377                         }
3378                 }
3379
3380                 m_loaded_blocks.insert(p, true);
3381         }
3382
3383         //dstream<<"emerge done"<<std::endl;
3384 }
3385 #endif
3386
3387 #if 0
3388 void MapVoxelManipulator::emerge(VoxelArea a)
3389 {
3390         TimeTaker timer1("emerge", &emerge_time);
3391         
3392         v3s16 size = a.getExtent();
3393         
3394         VoxelArea padded = a;
3395         padded.pad(m_area.getExtent() / 4);
3396         addArea(padded);
3397
3398         for(s16 z=0; z<size.Z; z++)
3399         for(s16 y=0; y<size.Y; y++)
3400         for(s16 x=0; x<size.X; x++)
3401         {
3402                 v3s16 p(x,y,z);
3403                 s32 i = m_area.index(a.MinEdge + p);
3404                 // Don't touch nodes that have already been loaded
3405                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
3406                         continue;
3407                 try
3408                 {
3409                         TimeTaker timer1("emerge load", &emerge_load_time);
3410                         MapNode n = m_map->getNode(a.MinEdge + p);
3411                         m_data[i] = n;
3412                         m_flags[i] = 0;
3413                 }
3414                 catch(InvalidPositionException &e)
3415                 {
3416                         m_flags[i] = VOXELFLAG_INEXISTENT;
3417                 }
3418         }
3419 }
3420 #endif
3421
3422
3423 /*
3424         TODO: Add an option to only update eg. water and air nodes.
3425               This will make it interfere less with important stuff if
3426                   run on background.
3427 */
3428 void MapVoxelManipulator::blitBack
3429                 (core::map<v3s16, MapBlock*> & modified_blocks)
3430 {
3431         if(m_area.getExtent() == v3s16(0,0,0))
3432                 return;
3433         
3434         //TimeTaker timer1("blitBack");
3435         
3436         /*
3437                 Initialize block cache
3438         */
3439         v3s16 blockpos_last;
3440         MapBlock *block = NULL;
3441         bool block_checked_in_modified = false;
3442
3443         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3444         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3445         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3446         {
3447                 v3s16 p(x,y,z);
3448
3449                 u8 f = m_flags[m_area.index(p)];
3450                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3451                         continue;
3452
3453                 MapNode &n = m_data[m_area.index(p)];
3454                         
3455                 v3s16 blockpos = getNodeBlockPos(p);
3456                 
3457                 try
3458                 {
3459                         // Get block
3460                         if(block == NULL || blockpos != blockpos_last){
3461                                 block = m_map->getBlockNoCreate(blockpos);
3462                                 blockpos_last = blockpos;
3463                                 block_checked_in_modified = false;
3464                         }
3465                         
3466                         // Calculate relative position in block
3467                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3468
3469                         // Don't continue if nothing has changed here
3470                         if(block->getNode(relpos) == n)
3471                                 continue;
3472
3473                         //m_map->setNode(m_area.MinEdge + p, n);
3474                         block->setNode(relpos, n);
3475                         
3476                         /*
3477                                 Make sure block is in modified_blocks
3478                         */
3479                         if(block_checked_in_modified == false)
3480                         {
3481                                 modified_blocks[blockpos] = block;
3482                                 block_checked_in_modified = true;
3483                         }
3484                 }
3485                 catch(InvalidPositionException &e)
3486                 {
3487                 }
3488         }
3489 }
3490
3491 //END