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