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