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