some work-in-progress
[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(is_underground)
1951         if(some_part_underground)
1952         {
1953                 s16 underground_level = (lowest_ground_y/MAP_BLOCKSIZE - block_y)+1;
1954                 for(s16 i=0; i<underground_level*3; i++)
1955                 {
1956                         if(rand()%2 == 0)
1957                         {
1958                                 v3s16 cp(
1959                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1960                                         (rand()%(MAP_BLOCKSIZE-2))+1,
1961                                         (rand()%(MAP_BLOCKSIZE-2))+1
1962                                 );
1963
1964                                 MapNode n;
1965                                 n.d = CONTENT_MESE;
1966                                 
1967                                 //if(is_ground_content(block->getNode(cp).d))
1968                                 if(block->getNode(cp).d == CONTENT_STONE)
1969                                         if(rand()%8 == 0)
1970                                                 block->setNode(cp, n);
1971
1972                                 for(u16 i=0; i<26; i++)
1973                                 {
1974                                         //if(is_ground_content(block->getNode(cp+g_26dirs[i]).d))
1975                                         if(block->getNode(cp+g_26dirs[i]).d == CONTENT_STONE)
1976                                                 if(rand()%8 == 0)
1977                                                         block->setNode(cp+g_26dirs[i], n);
1978                                 }
1979                         }
1980                 }
1981         }
1982         
1983         /*
1984                 Create a few rats in empty blocks underground
1985         */
1986         if(is_underground)
1987         {
1988                 //for(u16 i=0; i<2; i++)
1989                 {
1990                         v3s16 cp(
1991                                 (rand()%(MAP_BLOCKSIZE-2))+1,
1992                                 (rand()%(MAP_BLOCKSIZE-2))+1,
1993                                 (rand()%(MAP_BLOCKSIZE-2))+1
1994                         );
1995
1996                         // Check that the place is empty
1997                         //if(!is_ground_content(block->getNode(cp).d))
1998                         if(1)
1999                         {
2000                                 RatObject *obj = new RatObject(NULL, -1, intToFloat(cp));
2001                                 block->addObject(obj);
2002                         }
2003                 }
2004         }
2005         
2006         /*
2007                 Add block to sector.
2008         */
2009         sector->insertBlock(block);
2010         
2011         /*
2012                 Sector object stuff
2013         */
2014                 
2015         // An y-wise container of changed blocks
2016         core::map<s16, MapBlock*> changed_blocks_sector;
2017
2018         /*
2019                 Check if any sector's objects can be placed now.
2020                 If so, place them.
2021         */
2022         core::map<v3s16, u8> *objects = sector->getObjects();
2023         core::list<v3s16> objects_to_remove;
2024         for(core::map<v3s16, u8>::Iterator i = objects->getIterator();
2025                         i.atEnd() == false; i++)
2026         {
2027                 v3s16 p = i.getNode()->getKey();
2028                 v2s16 p2d(p.X,p.Z);
2029                 u8 d = i.getNode()->getValue();
2030
2031                 //v3s16 p = p_sector - v3s16(0, block_y*MAP_BLOCKSIZE, 0);
2032                 
2033                 try
2034                 {
2035
2036                 if(d == SECTOR_OBJECT_TEST)
2037                 {
2038                         if(sector->isValidArea(p + v3s16(0,0,0),
2039                                         p + v3s16(0,0,0), &changed_blocks_sector))
2040                         {
2041                                 MapNode n;
2042                                 n.d = CONTENT_TORCH;
2043                                 sector->setNode(p, n);
2044                                 objects_to_remove.push_back(p);
2045                         }
2046                 }
2047                 else if(d == SECTOR_OBJECT_TREE_1)
2048                 {
2049                         v3s16 p_min = p + v3s16(-1,0,-1);
2050                         v3s16 p_max = p + v3s16(1,4,1);
2051                         if(sector->isValidArea(p_min, p_max,
2052                                         &changed_blocks_sector))
2053                         {
2054                                 MapNode n;
2055                                 n.d = CONTENT_TREE;
2056                                 sector->setNode(p+v3s16(0,0,0), n);
2057                                 sector->setNode(p+v3s16(0,1,0), n);
2058                                 sector->setNode(p+v3s16(0,2,0), n);
2059                                 sector->setNode(p+v3s16(0,3,0), n);
2060
2061                                 n.d = CONTENT_LEAVES;
2062
2063                                 sector->setNode(p+v3s16(0,4,0), n);
2064                                 
2065                                 sector->setNode(p+v3s16(-1,4,0), n);
2066                                 sector->setNode(p+v3s16(1,4,0), n);
2067                                 sector->setNode(p+v3s16(0,4,-1), n);
2068                                 sector->setNode(p+v3s16(0,4,1), n);
2069                                 sector->setNode(p+v3s16(1,4,1), n);
2070                                 sector->setNode(p+v3s16(-1,4,1), n);
2071                                 sector->setNode(p+v3s16(-1,4,-1), n);
2072                                 sector->setNode(p+v3s16(1,4,-1), n);
2073
2074                                 sector->setNode(p+v3s16(-1,3,0), n);
2075                                 sector->setNode(p+v3s16(1,3,0), n);
2076                                 sector->setNode(p+v3s16(0,3,-1), n);
2077                                 sector->setNode(p+v3s16(0,3,1), n);
2078                                 sector->setNode(p+v3s16(1,3,1), n);
2079                                 sector->setNode(p+v3s16(-1,3,1), n);
2080                                 sector->setNode(p+v3s16(-1,3,-1), n);
2081                                 sector->setNode(p+v3s16(1,3,-1), n);
2082                                 
2083                                 objects_to_remove.push_back(p);
2084                                 
2085                                 // Lighting has to be recalculated for this one.
2086                                 sector->getBlocksInArea(p_min, p_max, 
2087                                                 lighting_invalidated_blocks);
2088                         }
2089                 }
2090                 else if(d == SECTOR_OBJECT_BUSH_1)
2091                 {
2092                         if(sector->isValidArea(p + v3s16(0,0,0),
2093                                         p + v3s16(0,0,0), &changed_blocks_sector))
2094                         {
2095                                 MapNode n;
2096                                 n.d = CONTENT_LEAVES;
2097                                 sector->setNode(p+v3s16(0,0,0), n);
2098                                 
2099                                 objects_to_remove.push_back(p);
2100                         }
2101                 }
2102                 else if(d == SECTOR_OBJECT_RAVINE)
2103                 {
2104                         s16 maxdepth = -20;
2105                         v3s16 p_min = p + v3s16(-6,maxdepth,-6);
2106                         v3s16 p_max = p + v3s16(6,6,6);
2107                         if(sector->isValidArea(p_min, p_max,
2108                                         &changed_blocks_sector))
2109                         {
2110                                 MapNode n;
2111                                 n.d = CONTENT_STONE;
2112                                 MapNode n2;
2113                                 n2.d = CONTENT_AIR;
2114                                 s16 depth = maxdepth + (rand()%10);
2115                                 s16 z = 0;
2116                                 s16 minz = -6 - (-2);
2117                                 s16 maxz = 6 -1;
2118                                 for(s16 x=-6; x<=6; x++)
2119                                 {
2120                                         z += -1 + (rand()%3);
2121                                         if(z < minz)
2122                                                 z = minz;
2123                                         if(z > maxz)
2124                                                 z = maxz;
2125                                         for(s16 y=depth+(rand()%2); y<=6; y++)
2126                                         {
2127                                                 /*std::cout<<"("<<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
2128                                                                 <<std::endl;*/
2129                                                 {
2130                                                         v3s16 p2 = p + v3s16(x,y,z-2);
2131                                                         if(is_ground_content(sector->getNode(p2).d))
2132                                                                 sector->setNode(p2, n);
2133                                                 }
2134                                                 {
2135                                                         v3s16 p2 = p + v3s16(x,y,z-1);
2136                                                         if(is_ground_content(sector->getNode(p2).d))
2137                                                                 sector->setNode(p2, n2);
2138                                                 }
2139                                                 {
2140                                                         v3s16 p2 = p + v3s16(x,y,z+0);
2141                                                         if(is_ground_content(sector->getNode(p2).d))
2142                                                                 sector->setNode(p2, n2);
2143                                                 }
2144                                                 {
2145                                                         v3s16 p2 = p + v3s16(x,y,z+1);
2146                                                         if(is_ground_content(sector->getNode(p2).d))
2147                                                                 sector->setNode(p2, n);
2148                                                 }
2149
2150                                                 //if(sector->getNode(p+v3s16(x,y,z+1)).solidness()==2)
2151                                                 //if(p.Y+y <= sector->getGroundHeight(p2d+v2s16(x,z-2))+0.5)
2152                                         }
2153                                 }
2154                                 
2155                                 objects_to_remove.push_back(p);
2156                                 
2157                                 // Lighting has to be recalculated for this one.
2158                                 sector->getBlocksInArea(p_min, p_max, 
2159                                                 lighting_invalidated_blocks);
2160                         }
2161                 }
2162                 else
2163                 {
2164                         dstream<<"ServerMap::emergeBlock(): "
2165                                         "Invalid heightmap object"
2166                                         <<std::endl;
2167                 }
2168
2169                 }//try
2170                 catch(InvalidPositionException &e)
2171                 {
2172                         dstream<<"WARNING: "<<__FUNCTION_NAME
2173                                         <<": while inserting object "<<(int)d
2174                                         <<" to ("<<p.X<<","<<p.Y<<","<<p.Z<<"):"
2175                                         <<" InvalidPositionException.what()="
2176                                         <<e.what()<<std::endl;
2177                         // This is not too fatal and seems to happen sometimes.
2178                         assert(0);
2179                 }
2180         }
2181
2182         for(core::list<v3s16>::Iterator i = objects_to_remove.begin();
2183                         i != objects_to_remove.end(); i++)
2184         {
2185                 objects->remove(*i);
2186         }
2187
2188         for(core::map<s16, MapBlock*>::Iterator
2189                         i = changed_blocks_sector.getIterator();
2190                         i.atEnd() == false; i++)
2191         {
2192                 MapBlock *block = i.getNode()->getValue();
2193
2194                 changed_blocks.insert(block->getPos(), block);
2195         }
2196
2197         return block;
2198 }
2199
2200 void ServerMap::createDir(std::string path)
2201 {
2202         if(fs::CreateDir(path) == false)
2203         {
2204                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2205                                 <<"\""<<path<<"\""<<std::endl;
2206                 throw BaseException("ServerMap failed to create directory");
2207         }
2208 }
2209
2210 std::string ServerMap::getSectorSubDir(v2s16 pos)
2211 {
2212         char cc[9];
2213         snprintf(cc, 9, "%.4x%.4x",
2214                         (unsigned int)pos.X&0xffff,
2215                         (unsigned int)pos.Y&0xffff);
2216
2217         return std::string(cc);
2218 }
2219
2220 std::string ServerMap::getSectorDir(v2s16 pos)
2221 {
2222         return m_savedir + "/sectors/" + getSectorSubDir(pos);
2223 }
2224
2225 v2s16 ServerMap::getSectorPos(std::string dirname)
2226 {
2227         if(dirname.size() != 8)
2228                 throw InvalidFilenameException("Invalid sector directory name");
2229         unsigned int x, y;
2230         int r = sscanf(dirname.c_str(), "%4x%4x", &x, &y);
2231         if(r != 2)
2232                 throw InvalidFilenameException("Invalid sector directory name");
2233         v2s16 pos((s16)x, (s16)y);
2234         return pos;
2235 }
2236
2237 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2238 {
2239         v2s16 p2d = getSectorPos(sectordir);
2240
2241         if(blockfile.size() != 4){
2242                 throw InvalidFilenameException("Invalid block filename");
2243         }
2244         unsigned int y;
2245         int r = sscanf(blockfile.c_str(), "%4x", &y);
2246         if(r != 1)
2247                 throw InvalidFilenameException("Invalid block filename");
2248         return v3s16(p2d.X, y, p2d.Y);
2249 }
2250
2251 // Debug helpers
2252 #define ENABLE_SECTOR_SAVING 1
2253 #define ENABLE_SECTOR_LOADING 1
2254 #define ENABLE_BLOCK_SAVING 1
2255 #define ENABLE_BLOCK_LOADING 1
2256
2257 void ServerMap::save(bool only_changed)
2258 {
2259         DSTACK(__FUNCTION_NAME);
2260         if(m_map_saving_enabled == false)
2261         {
2262                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2263                 return;
2264         }
2265         
2266         if(only_changed == false)
2267                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2268                                 <<std::endl;
2269         
2270         saveMasterHeightmap();
2271         
2272         u32 sector_meta_count = 0;
2273         u32 block_count = 0;
2274         
2275         { //sectorlock
2276         JMutexAutoLock lock(m_sector_mutex);
2277         
2278         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2279         for(; i.atEnd() == false; i++)
2280         {
2281                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2282                 assert(sector->getId() == MAPSECTOR_SERVER);
2283                 
2284                 if(ENABLE_SECTOR_SAVING)
2285                 {
2286                         if(sector->differs_from_disk || only_changed == false)
2287                         {
2288                                 saveSectorMeta(sector);
2289                                 sector_meta_count++;
2290                         }
2291                 }
2292                 if(ENABLE_BLOCK_SAVING)
2293                 {
2294                         core::list<MapBlock*> blocks;
2295                         sector->getBlocks(blocks);
2296                         core::list<MapBlock*>::Iterator j;
2297                         for(j=blocks.begin(); j!=blocks.end(); j++)
2298                         {
2299                                 MapBlock *block = *j;
2300                                 if(block->getChangedFlag() || only_changed == false)
2301                                 {
2302                                         saveBlock(block);
2303                                         block_count++;
2304                                 }
2305                         }
2306                 }
2307         }
2308
2309         }//sectorlock
2310         
2311         /*
2312                 Only print if something happened or saved whole map
2313         */
2314         if(only_changed == false || sector_meta_count != 0
2315                         || block_count != 0)
2316         {
2317                 dstream<<DTIME<<"ServerMap: Written: "
2318                                 <<sector_meta_count<<" sector metadata files, "
2319                                 <<block_count<<" block files"
2320                                 <<std::endl;
2321         }
2322 }
2323
2324 void ServerMap::loadAll()
2325 {
2326         DSTACK(__FUNCTION_NAME);
2327         dstream<<DTIME<<"ServerMap: Loading map..."<<std::endl;
2328
2329         loadMasterHeightmap();
2330
2331         std::vector<fs::DirListNode> list = fs::GetDirListing(m_savedir+"/sectors/");
2332
2333         dstream<<DTIME<<"There are "<<list.size()<<" sectors."<<std::endl;
2334         
2335         JMutexAutoLock lock(m_sector_mutex);
2336         
2337         s32 counter = 0;
2338         s32 printed_counter = -100000;
2339         s32 count = list.size();
2340
2341         std::vector<fs::DirListNode>::iterator i;
2342         for(i=list.begin(); i!=list.end(); i++)
2343         {
2344                 if(counter > printed_counter + 10)
2345                 {
2346                         dstream<<DTIME<<counter<<"/"<<count<<std::endl;
2347                         printed_counter = counter;
2348                 }
2349                 counter++;
2350
2351                 MapSector *sector = NULL;
2352
2353                 // We want directories
2354                 if(i->dir == false)
2355                         continue;
2356                 try{
2357                         sector = loadSectorMeta(i->name);
2358                 }
2359                 catch(InvalidFilenameException &e)
2360                 {
2361                         // This catches unknown crap in directory
2362                 }
2363                 
2364                 if(ENABLE_BLOCK_LOADING)
2365                 {
2366                         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2367                                         (m_savedir+"/sectors/"+i->name);
2368                         std::vector<fs::DirListNode>::iterator i2;
2369                         for(i2=list2.begin(); i2!=list2.end(); i2++)
2370                         {
2371                                 // We want files
2372                                 if(i2->dir)
2373                                         continue;
2374                                 try{
2375                                         loadBlock(i->name, i2->name, sector);
2376                                 }
2377                                 catch(InvalidFilenameException &e)
2378                                 {
2379                                         // This catches unknown crap in directory
2380                                 }
2381                         }
2382                 }
2383         }
2384         dstream<<DTIME<<"ServerMap: Map loaded."<<std::endl;
2385 }
2386
2387 void ServerMap::saveMasterHeightmap()
2388 {
2389         DSTACK(__FUNCTION_NAME);
2390         createDir(m_savedir);
2391         
2392         std::string fullpath = m_savedir + "/master_heightmap";
2393         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2394         if(o.good() == false)
2395                 throw FileNotGoodException("Cannot open master heightmap");
2396         
2397         // Format used for writing
2398         u8 version = SER_FMT_VER_HIGHEST;
2399
2400 #if 0
2401         SharedBuffer<u8> hmdata = m_heightmap->serialize(version);
2402         /*
2403                 [0] u8 serialization version
2404                 [1] X master heightmap
2405         */
2406         u32 fullsize = 1 + hmdata.getSize();
2407         SharedBuffer<u8> data(fullsize);
2408
2409         data[0] = version;
2410         memcpy(&data[1], *hmdata, hmdata.getSize());
2411
2412         o.write((const char*)*data, fullsize);
2413 #endif
2414         
2415         m_heightmap->serialize(o, version);
2416 }
2417
2418 void ServerMap::loadMasterHeightmap()
2419 {
2420         DSTACK(__FUNCTION_NAME);
2421         std::string fullpath = m_savedir + "/master_heightmap";
2422         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2423         if(is.good() == false)
2424                 throw FileNotGoodException("Cannot open master heightmap");
2425         
2426         if(m_heightmap != NULL)
2427                 delete m_heightmap;
2428                 
2429         m_heightmap = UnlimitedHeightmap::deSerialize(is);
2430 }
2431
2432 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2433 {
2434         DSTACK(__FUNCTION_NAME);
2435         // Format used for writing
2436         u8 version = SER_FMT_VER_HIGHEST;
2437         // Get destination
2438         v2s16 pos = sector->getPos();
2439         createDir(m_savedir);
2440         createDir(m_savedir+"/sectors");
2441         std::string dir = getSectorDir(pos);
2442         createDir(dir);
2443         
2444         std::string fullpath = dir + "/heightmap";
2445         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2446         if(o.good() == false)
2447                 throw FileNotGoodException("Cannot open master heightmap");
2448
2449         sector->serialize(o, version);
2450         
2451         sector->differs_from_disk = false;
2452 }
2453
2454 MapSector* ServerMap::loadSectorMeta(std::string dirname)
2455 {
2456         DSTACK(__FUNCTION_NAME);
2457         // Get destination
2458         v2s16 p2d = getSectorPos(dirname);
2459         std::string dir = m_savedir + "/sectors/" + dirname;
2460         
2461         std::string fullpath = dir + "/heightmap";
2462         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2463         if(is.good() == false)
2464                 throw FileNotGoodException("Cannot open sector heightmap");
2465
2466         ServerMapSector *sector = ServerMapSector::deSerialize
2467                         (is, this, p2d, &m_hwrapper, m_sectors);
2468         
2469         sector->differs_from_disk = false;
2470
2471         return sector;
2472 }
2473
2474 bool ServerMap::loadSectorFull(v2s16 p2d)
2475 {
2476         DSTACK(__FUNCTION_NAME);
2477         std::string sectorsubdir = getSectorSubDir(p2d);
2478
2479         MapSector *sector = NULL;
2480
2481         JMutexAutoLock lock(m_sector_mutex);
2482
2483         try{
2484                 sector = loadSectorMeta(sectorsubdir);
2485         }
2486         catch(InvalidFilenameException &e)
2487         {
2488                 return false;
2489         }
2490         catch(FileNotGoodException &e)
2491         {
2492                 return false;
2493         }
2494         catch(std::exception &e)
2495         {
2496                 return false;
2497         }
2498
2499         if(ENABLE_BLOCK_LOADING)
2500         {
2501                 std::vector<fs::DirListNode> list2 = fs::GetDirListing
2502                                 (m_savedir+"/sectors/"+sectorsubdir);
2503                 std::vector<fs::DirListNode>::iterator i2;
2504                 for(i2=list2.begin(); i2!=list2.end(); i2++)
2505                 {
2506                         // We want files
2507                         if(i2->dir)
2508                                 continue;
2509                         try{
2510                                 loadBlock(sectorsubdir, i2->name, sector);
2511                         }
2512                         catch(InvalidFilenameException &e)
2513                         {
2514                                 // This catches unknown crap in directory
2515                         }
2516                 }
2517         }
2518         return true;
2519 }
2520
2521 #if 0
2522 bool ServerMap::deFlushSector(v2s16 p2d)
2523 {
2524         DSTACK(__FUNCTION_NAME);
2525         // See if it already exists in memory
2526         try{
2527                 MapSector *sector = getSectorNoGenerate(p2d);
2528                 return true;
2529         }
2530         catch(InvalidPositionException &e)
2531         {
2532                 /*
2533                         Try to load the sector from disk.
2534                 */
2535                 if(loadSectorFull(p2d) == true)
2536                 {
2537                         return true;
2538                 }
2539         }
2540         return false;
2541 }
2542 #endif
2543
2544 void ServerMap::saveBlock(MapBlock *block)
2545 {
2546         DSTACK(__FUNCTION_NAME);
2547         /*
2548                 Dummy blocks are not written
2549         */
2550         if(block->isDummy())
2551         {
2552                 /*v3s16 p = block->getPos();
2553                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
2554                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
2555                 return;
2556         }
2557
2558         // Format used for writing
2559         u8 version = SER_FMT_VER_HIGHEST;
2560         // Get destination
2561         v3s16 p3d = block->getPos();
2562         v2s16 p2d(p3d.X, p3d.Z);
2563         createDir(m_savedir);
2564         createDir(m_savedir+"/sectors");
2565         std::string dir = getSectorDir(p2d);
2566         createDir(dir);
2567         
2568         // Block file is map/sectors/xxxxxxxx/xxxx
2569         char cc[5];
2570         snprintf(cc, 5, "%.4x", (unsigned int)p3d.Y&0xffff);
2571         std::string fullpath = dir + "/" + cc;
2572         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2573         if(o.good() == false)
2574                 throw FileNotGoodException("Cannot open block data");
2575
2576         /*
2577                 [0] u8 serialization version
2578                 [1] data
2579         */
2580         o.write((char*)&version, 1);
2581         
2582         block->serialize(o, version);
2583
2584         /*
2585                 Versions up from 9 have block objects.
2586         */
2587         if(version >= 9)
2588         {
2589                 block->serializeObjects(o, version);
2590         }
2591         
2592         // We just wrote it to the disk
2593         block->resetChangedFlag();
2594 }
2595
2596 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector)
2597 {
2598         DSTACK(__FUNCTION_NAME);
2599
2600         try{
2601
2602         // Block file is map/sectors/xxxxxxxx/xxxx
2603         std::string fullpath = m_savedir+"/sectors/"+sectordir+"/"+blockfile;
2604         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2605         if(is.good() == false)
2606                 throw FileNotGoodException("Cannot open block file");
2607
2608         v3s16 p3d = getBlockPos(sectordir, blockfile);
2609         v2s16 p2d(p3d.X, p3d.Z);
2610         
2611         assert(sector->getPos() == p2d);
2612         
2613         u8 version = SER_FMT_VER_INVALID;
2614         is.read((char*)&version, 1);
2615
2616         /*u32 block_size = MapBlock::serializedLength(version);
2617         SharedBuffer<u8> data(block_size);
2618         is.read((char*)*data, block_size);*/
2619
2620         // This will always return a sector because we're the server
2621         //MapSector *sector = emergeSector(p2d);
2622
2623         MapBlock *block = NULL;
2624         bool created_new = false;
2625         try{
2626                 block = sector->getBlockNoCreate(p3d.Y);
2627         }
2628         catch(InvalidPositionException &e)
2629         {
2630                 block = sector->createBlankBlockNoInsert(p3d.Y);
2631                 created_new = true;
2632         }
2633         
2634         // deserialize block data
2635         block->deSerialize(is, version);
2636         
2637         /*
2638                 Versions up from 9 have block objects.
2639         */
2640         if(version >= 9)
2641         {
2642                 block->updateObjects(is, version, NULL, 0);
2643         }
2644
2645         if(created_new)
2646                 sector->insertBlock(block);
2647         
2648         /*
2649                 Convert old formats to new and save
2650         */
2651
2652         // Save old format blocks in new format
2653         if(version < SER_FMT_VER_HIGHEST)
2654         {
2655                 saveBlock(block);
2656         }
2657         
2658         // We just loaded it from the disk, so it's up-to-date.
2659         block->resetChangedFlag();
2660
2661         }
2662         catch(SerializationError &e)
2663         {
2664                 dstream<<"WARNING: Invalid block data on disk "
2665                                 "(SerializationError). Ignoring."
2666                                 <<std::endl;
2667         }
2668 }
2669
2670 // Gets from master heightmap
2671 void ServerMap::getSectorCorners(v2s16 p2d, s16 *corners)
2672 {
2673         assert(m_heightmap != NULL);
2674         /*
2675                 Corner definition:
2676                 v2s16(0,0),
2677                 v2s16(1,0),
2678                 v2s16(1,1),
2679                 v2s16(0,1),
2680         */
2681         corners[0] = m_heightmap->getGroundHeight
2682                         ((p2d+v2s16(0,0))*SECTOR_HEIGHTMAP_SPLIT);
2683         corners[1] = m_heightmap->getGroundHeight
2684                         ((p2d+v2s16(1,0))*SECTOR_HEIGHTMAP_SPLIT);
2685         corners[2] = m_heightmap->getGroundHeight
2686                         ((p2d+v2s16(1,1))*SECTOR_HEIGHTMAP_SPLIT);
2687         corners[3] = m_heightmap->getGroundHeight
2688                         ((p2d+v2s16(0,1))*SECTOR_HEIGHTMAP_SPLIT);
2689 }
2690
2691 void ServerMap::PrintInfo(std::ostream &out)
2692 {
2693         out<<"ServerMap: ";
2694 }
2695
2696 #ifndef SERVER
2697
2698 /*
2699         ClientMap
2700 */
2701
2702 ClientMap::ClientMap(
2703                 Client *client,
2704                 JMutex &range_mutex,
2705                 s16 &viewing_range_nodes,
2706                 bool &viewing_range_all,
2707                 scene::ISceneNode* parent,
2708                 scene::ISceneManager* mgr,
2709                 s32 id
2710 ):
2711         Map(dout_client),
2712         scene::ISceneNode(parent, mgr, id),
2713         m_client(client),
2714         mesh(NULL),
2715         m_range_mutex(range_mutex),
2716         m_viewing_range_nodes(viewing_range_nodes),
2717         m_viewing_range_all(viewing_range_all)
2718 {
2719         mesh_mutex.Init();
2720
2721         /*m_box = core::aabbox3d<f32>(0,0,0,
2722                         map->getW()*BS, map->getH()*BS, map->getD()*BS);*/
2723         /*m_box = core::aabbox3d<f32>(0,0,0,
2724                         map->getSizeNodes().X * BS,
2725                         map->getSizeNodes().Y * BS,
2726                         map->getSizeNodes().Z * BS);*/
2727         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
2728                         BS*1000000,BS*1000000,BS*1000000);
2729         
2730         //setPosition(v3f(BS,BS,BS));
2731 }
2732
2733 ClientMap::~ClientMap()
2734 {
2735         JMutexAutoLock lock(mesh_mutex);
2736         
2737         if(mesh != NULL)
2738         {
2739                 mesh->drop();
2740                 mesh = NULL;
2741         }
2742 }
2743
2744 MapSector * ClientMap::emergeSector(v2s16 p2d)
2745 {
2746         DSTACK(__FUNCTION_NAME);
2747         // Check that it doesn't exist already
2748         try{
2749                 return getSectorNoGenerate(p2d);
2750         }
2751         catch(InvalidPositionException &e)
2752         {
2753         }
2754         
2755         // Create a sector with no heightmaps
2756         ClientMapSector *sector = new ClientMapSector(this, p2d);
2757         
2758         {
2759                 JMutexAutoLock lock(m_sector_mutex);
2760                 m_sectors.insert(p2d, sector);
2761         }
2762         
2763         return sector;
2764 }
2765
2766 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
2767 {
2768         DSTACK(__FUNCTION_NAME);
2769         ClientMapSector *sector = NULL;
2770
2771         JMutexAutoLock lock(m_sector_mutex);
2772         
2773         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
2774
2775         if(n != NULL)
2776         {
2777                 sector = (ClientMapSector*)n->getValue();
2778                 assert(sector->getId() == MAPSECTOR_CLIENT);
2779         }
2780         else
2781         {
2782                 sector = new ClientMapSector(this, p2d);
2783                 {
2784                         JMutexAutoLock lock(m_sector_mutex);
2785                         m_sectors.insert(p2d, sector);
2786                 }
2787         }
2788
2789         sector->deSerialize(is);
2790 }
2791
2792 void ClientMap::OnRegisterSceneNode()
2793 {
2794         if(IsVisible)
2795         {
2796                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
2797                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
2798         }
2799
2800         ISceneNode::OnRegisterSceneNode();
2801 }
2802
2803 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
2804 {
2805         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
2806         DSTACK(__FUNCTION_NAME);
2807
2808         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
2809
2810         /*
2811                 Get time for measuring timeout.
2812                 
2813                 Measuring time is very useful for long delays when the
2814                 machine is swapping a lot.
2815         */
2816         int time1 = time(0);
2817
2818         //s32 daynight_i = m_client->getDayNightIndex();
2819         u32 daynight_ratio = m_client->getDayNightRatio();
2820
2821         /*
2822                 Collect all blocks that are in the view range
2823
2824                 Should not optimize more here as we want to auto-update
2825                 all changed nodes in viewing range at the next step.
2826         */
2827
2828         s16 viewing_range_nodes;
2829         bool viewing_range_all;
2830         {
2831                 JMutexAutoLock lock(m_range_mutex);
2832                 viewing_range_nodes = m_viewing_range_nodes;
2833                 viewing_range_all = m_viewing_range_all;
2834         }
2835
2836         m_camera_mutex.Lock();
2837         v3f camera_position = m_camera_position;
2838         v3f camera_direction = m_camera_direction;
2839         m_camera_mutex.Unlock();
2840
2841         /*
2842                 Get all blocks and draw all visible ones
2843         */
2844
2845         v3s16 cam_pos_nodes(
2846                         camera_position.X / BS,
2847                         camera_position.Y / BS,
2848                         camera_position.Z / BS);
2849
2850         v3s16 box_nodes_d = viewing_range_nodes * v3s16(1,1,1);
2851
2852         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
2853         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
2854
2855         // Take a fair amount as we will be dropping more out later
2856         v3s16 p_blocks_min(
2857                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
2858                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
2859                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
2860         v3s16 p_blocks_max(
2861                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
2862                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
2863                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
2864         
2865         u32 vertex_count = 0;
2866         
2867         // For limiting number of mesh updates per frame
2868         u32 mesh_update_count = 0;
2869
2870         //NOTE: The sectors map should be locked but we're not doing it
2871         // because it'd cause too much delays
2872
2873         int timecheck_counter = 0;
2874
2875         core::map<v2s16, MapSector*>::Iterator si;
2876         si = m_sectors.getIterator();
2877         for(; si.atEnd() == false; si++)
2878         {
2879                 {
2880                         timecheck_counter++;
2881                         if(timecheck_counter > 50)
2882                         {
2883                                 int time2 = time(0);
2884                                 if(time2 > time1 + 4)
2885                                 {
2886                                         dstream<<"ClientMap::renderMap(): "
2887                                                 "Rendering takes ages, returning."
2888                                                 <<std::endl;
2889                                         return;
2890                                 }
2891                         }
2892                 }
2893
2894                 MapSector *sector = si.getNode()->getValue();
2895                 v2s16 sp = sector->getPos();
2896                 
2897                 if(viewing_range_all == false)
2898                 {
2899                         if(sp.X < p_blocks_min.X
2900                         || sp.X > p_blocks_max.X
2901                         || sp.Y < p_blocks_min.Z
2902                         || sp.Y > p_blocks_max.Z)
2903                                 continue;
2904                 }
2905
2906                 core::list< MapBlock * > sectorblocks;
2907                 sector->getBlocks(sectorblocks);
2908                 
2909                 /*
2910                         Draw blocks
2911                 */
2912
2913                 core::list< MapBlock * >::Iterator i;
2914                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
2915                 {
2916                         MapBlock *block = *i;
2917
2918                         /*
2919                                 Compare block position to camera position, skip
2920                                 if not seen on display
2921                         */
2922                         
2923                         v3s16 blockpos_nodes = block->getPosRelative();
2924                         
2925                         // Block center position
2926                         v3f blockpos(
2927                                         ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
2928                                         ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
2929                                         ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
2930                         );
2931
2932                         // Block position relative to camera
2933                         v3f blockpos_relative = blockpos - camera_position;
2934
2935                         // Distance in camera direction (+=front, -=back)
2936                         f32 dforward = blockpos_relative.dotProduct(camera_direction);
2937
2938                         // Total distance
2939                         f32 d = blockpos_relative.getLength();
2940                         
2941                         if(viewing_range_all == false)
2942                         {
2943                                 // If block is far away, don't draw it
2944                                 if(d > viewing_range_nodes * BS)
2945                                 // This is nicer when fog is used
2946                                 //if((dforward+d)/2 > viewing_range_nodes * BS)
2947                                         continue;
2948                         }
2949                         
2950                         // Maximum radius of a block
2951                         f32 block_max_radius = 0.5*1.44*1.44*MAP_BLOCKSIZE*BS;
2952                         
2953                         // If block is (nearly) touching the camera, don't
2954                         // bother validating further (that is, render it anyway)
2955                         if(d > block_max_radius * 1.5)
2956                         {
2957                                 // Cosine of the angle between the camera direction
2958                                 // and the block direction (camera_direction is an unit vector)
2959                                 f32 cosangle = dforward / d;
2960                                 
2961                                 // Compensate for the size of the block
2962                                 // (as the block has to be shown even if it's a bit off FOV)
2963                                 // This is an estimate.
2964                                 cosangle += block_max_radius / dforward;
2965
2966                                 // If block is not in the field of view, skip it
2967                                 //if(cosangle < cos(FOV_ANGLE/2))
2968                                 if(cosangle < cos(FOV_ANGLE/2. * 4./3.))
2969                                         continue;
2970                         }
2971                         
2972                         /*
2973                                 Draw the faces of the block
2974                         */
2975 #if 1
2976                         bool mesh_expired = false;
2977                         
2978                         {
2979                                 JMutexAutoLock lock(block->mesh_mutex);
2980
2981                                 mesh_expired = block->getMeshExpired();
2982
2983                                 // Mesh has not been expired and there is no mesh:
2984                                 // block has no content
2985                                 if(block->mesh == NULL && mesh_expired == false)
2986                                         continue;
2987                         }
2988
2989                         f32 faraway = BS*50;
2990                         //f32 faraway = viewing_range_nodes * BS;
2991                         
2992                         /*
2993                                 This has to be done with the mesh_mutex unlocked
2994                         */
2995                         if(mesh_expired && mesh_update_count < 6
2996                                         && (d < faraway || mesh_update_count < 3))
2997                         //if(mesh_expired && mesh_update_count < 4)
2998                         {
2999                                 mesh_update_count++;
3000
3001                                 // Mesh has been expired: generate new mesh
3002                                 //block->updateMeshes(daynight_i);
3003                                 block->updateMesh(daynight_ratio);
3004
3005                                 mesh_expired = false;
3006                         }
3007                         
3008                         /*
3009                                 Don't draw an expired mesh that is far away
3010                         */
3011                         /*if(mesh_expired && d >= faraway)
3012                         //if(mesh_expired)
3013                         {
3014                                 // Instead, delete it
3015                                 JMutexAutoLock lock(block->mesh_mutex);
3016                                 if(block->mesh)
3017                                 {
3018                                         block->mesh->drop();
3019                                         block->mesh = NULL;
3020                                 }
3021                                 // And continue to next block
3022                                 continue;
3023                         }*/
3024 #endif
3025                         {
3026                                 JMutexAutoLock lock(block->mesh_mutex);
3027
3028                                 scene::SMesh *mesh = block->mesh;
3029
3030                                 if(mesh == NULL)
3031                                         continue;
3032
3033                                 u32 c = mesh->getMeshBufferCount();
3034
3035                                 for(u32 i=0; i<c; i++)
3036                                 {
3037                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3038                                         const video::SMaterial& material = buf->getMaterial();
3039                                         video::IMaterialRenderer* rnd =
3040                                                         driver->getMaterialRenderer(material.MaterialType);
3041                                         bool transparent = (rnd && rnd->isTransparent());
3042                                         // Render transparent on transparent pass and likewise.
3043                                         if(transparent == is_transparent_pass)
3044                                         {
3045                                                 driver->setMaterial(buf->getMaterial());
3046                                                 driver->drawMeshBuffer(buf);
3047                                                 vertex_count += buf->getVertexCount();
3048                                         }
3049                                 }
3050                         }
3051                 } // foreach sectorblocks
3052         }
3053
3054         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3055                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3056 }
3057
3058 v3s16 ClientMap::setTempMod(v3s16 p, NodeMod mod)
3059 {
3060         /*
3061                 Add it to all blocks touching it
3062         */
3063         v3s16 dirs[7] = {
3064                 v3s16(0,0,0), // this
3065                 v3s16(0,0,1), // back
3066                 v3s16(0,1,0), // top
3067                 v3s16(1,0,0), // right
3068                 v3s16(0,0,-1), // front
3069                 v3s16(0,-1,0), // bottom
3070                 v3s16(-1,0,0), // left
3071         };
3072         for(u16 i=0; i<7; i++)
3073         {
3074                 v3s16 p2 = p + dirs[i];
3075                 // Block position of neighbor (or requested) node
3076                 v3s16 blockpos = getNodeBlockPos(p2);
3077                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3078                 if(blockref == NULL)
3079                         continue;
3080                 // Relative position of requested node
3081                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3082                 blockref->setTempMod(relpos, mod);
3083         }
3084         return getNodeBlockPos(p);
3085 }
3086 v3s16 ClientMap::clearTempMod(v3s16 p)
3087 {
3088         v3s16 dirs[7] = {
3089                 v3s16(0,0,0), // this
3090                 v3s16(0,0,1), // back
3091                 v3s16(0,1,0), // top
3092                 v3s16(1,0,0), // right
3093                 v3s16(0,0,-1), // front
3094                 v3s16(0,-1,0), // bottom
3095                 v3s16(-1,0,0), // left
3096         };
3097         for(u16 i=0; i<7; i++)
3098         {
3099                 v3s16 p2 = p + dirs[i];
3100                 // Block position of neighbor (or requested) node
3101                 v3s16 blockpos = getNodeBlockPos(p2);
3102                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3103                 if(blockref == NULL)
3104                         continue;
3105                 // Relative position of requested node
3106                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3107                 blockref->clearTempMod(relpos);
3108         }
3109         return getNodeBlockPos(p);
3110 }
3111
3112 void ClientMap::PrintInfo(std::ostream &out)
3113 {
3114         out<<"ClientMap: ";
3115 }
3116
3117 #endif // !SERVER
3118
3119 /*
3120         MapVoxelManipulator
3121 */
3122
3123 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3124 {
3125         m_map = map;
3126 }
3127
3128 MapVoxelManipulator::~MapVoxelManipulator()
3129 {
3130         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3131                         <<std::endl;*/
3132 }
3133
3134 #if 1
3135 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3136 {
3137         TimeTaker timer1("emerge", &emerge_time);
3138
3139         // Units of these are MapBlocks
3140         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3141         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3142
3143         VoxelArea block_area_nodes
3144                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3145
3146         addArea(block_area_nodes);
3147
3148         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3149         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3150         for(s32 x=p_min.X; x<=p_max.X; x++)
3151         {
3152                 v3s16 p(x,y,z);
3153                 core::map<v3s16, bool>::Node *n;
3154                 n = m_loaded_blocks.find(p);
3155                 if(n != NULL)
3156                         continue;
3157                 
3158                 bool block_data_inexistent = false;
3159                 try
3160                 {
3161                         TimeTaker timer1("emerge load", &emerge_load_time);
3162
3163                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3164                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3165                                         <<" wanted area: ";
3166                         a.print(dstream);
3167                         dstream<<std::endl;*/
3168                         
3169                         MapBlock *block = m_map->getBlockNoCreate(p);
3170                         if(block->isDummy())
3171                                 block_data_inexistent = true;
3172                         else
3173                                 block->copyTo(*this);
3174                 }
3175                 catch(InvalidPositionException &e)
3176                 {
3177                         block_data_inexistent = true;
3178                 }
3179
3180                 if(block_data_inexistent)
3181                 {
3182                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3183                         // Fill with VOXELFLAG_INEXISTENT
3184                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3185                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3186                         {
3187                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3188                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3189                         }
3190                 }
3191
3192                 m_loaded_blocks.insert(p, true);
3193         }
3194
3195         //dstream<<"emerge done"<<std::endl;
3196 }
3197 #endif
3198
3199 #if 0
3200 void MapVoxelManipulator::emerge(VoxelArea a)
3201 {
3202         TimeTaker timer1("emerge", &emerge_time);
3203         
3204         v3s16 size = a.getExtent();
3205         
3206         VoxelArea padded = a;
3207         padded.pad(m_area.getExtent() / 4);
3208         addArea(padded);
3209
3210         for(s16 z=0; z<size.Z; z++)
3211         for(s16 y=0; y<size.Y; y++)
3212         for(s16 x=0; x<size.X; x++)
3213         {
3214                 v3s16 p(x,y,z);
3215                 s32 i = m_area.index(a.MinEdge + p);
3216                 // Don't touch nodes that have already been loaded
3217                 if(!(m_flags[i] & VOXELFLAG_NOT_LOADED))
3218                         continue;
3219                 try
3220                 {
3221                         TimeTaker timer1("emerge load", &emerge_load_time);
3222                         MapNode n = m_map->getNode(a.MinEdge + p);
3223                         m_data[i] = n;
3224                         m_flags[i] = 0;
3225                 }
3226                 catch(InvalidPositionException &e)
3227                 {
3228                         m_flags[i] = VOXELFLAG_INEXISTENT;
3229                 }
3230         }
3231 }
3232 #endif
3233
3234
3235 /*
3236         TODO: Add an option to only update eg. water and air nodes.
3237               This will make it interfere less with important stuff if
3238                   run on background.
3239 */
3240 void MapVoxelManipulator::blitBack
3241                 (core::map<v3s16, MapBlock*> & modified_blocks)
3242 {
3243         if(m_area.getExtent() == v3s16(0,0,0))
3244                 return;
3245         
3246         //TimeTaker timer1("blitBack");
3247         
3248         /*
3249                 Initialize block cache
3250         */
3251         v3s16 blockpos_last;
3252         MapBlock *block = NULL;
3253         bool block_checked_in_modified = false;
3254
3255         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3256         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3257         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3258         {
3259                 v3s16 p(x,y,z);
3260
3261                 u8 f = m_flags[m_area.index(p)];
3262                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3263                         continue;
3264
3265                 MapNode &n = m_data[m_area.index(p)];
3266                         
3267                 v3s16 blockpos = getNodeBlockPos(p);
3268                 
3269                 try
3270                 {
3271                         // Get block
3272                         if(block == NULL || blockpos != blockpos_last){
3273                                 block = m_map->getBlockNoCreate(blockpos);
3274                                 blockpos_last = blockpos;
3275                                 block_checked_in_modified = false;
3276                         }
3277                         
3278                         // Calculate relative position in block
3279                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3280
3281                         // Don't continue if nothing has changed here
3282                         if(block->getNode(relpos) == n)
3283                                 continue;
3284
3285                         //m_map->setNode(m_area.MinEdge + p, n);
3286                         block->setNode(relpos, n);
3287                         
3288                         /*
3289                                 Make sure block is in modified_blocks
3290                         */
3291                         if(block_checked_in_modified == false)
3292                         {
3293                                 modified_blocks[blockpos] = block;
3294                                 block_checked_in_modified = true;
3295                         }
3296                 }
3297                 catch(InvalidPositionException &e)
3298                 {
3299                 }
3300         }
3301 }
3302
3303 //END