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