Flowing lava updates lighting
[oweals/minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 "mapsector.h"
22 #include "mapblock.h"
23 #include "main.h"
24 #include "client.h"
25 #include "filesys.h"
26 #include "utility.h"
27 #include "voxel.h"
28 #include "porting.h"
29 #include "mapgen.h"
30 #include "nodemetadata.h"
31
32 extern "C" {
33         #include "sqlite3.h"
34 }
35 /*
36         SQLite format specification:
37         - Initially only replaces sectors/ and sectors2/
38 */
39
40 /*
41         Map
42 */
43
44 Map::Map(std::ostream &dout):
45         m_dout(dout),
46         m_sector_cache(NULL)
47 {
48         /*m_sector_mutex.Init();
49         assert(m_sector_mutex.IsInitialized());*/
50 }
51
52 Map::~Map()
53 {
54         /*
55                 Free all MapSectors
56         */
57         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
58         for(; i.atEnd() == false; i++)
59         {
60                 MapSector *sector = i.getNode()->getValue();
61                 delete sector;
62         }
63 }
64
65 void Map::addEventReceiver(MapEventReceiver *event_receiver)
66 {
67         m_event_receivers.insert(event_receiver, false);
68 }
69
70 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
71 {
72         if(m_event_receivers.find(event_receiver) == NULL)
73                 return;
74         m_event_receivers.remove(event_receiver);
75 }
76
77 void Map::dispatchEvent(MapEditEvent *event)
78 {
79         for(core::map<MapEventReceiver*, bool>::Iterator
80                         i = m_event_receivers.getIterator();
81                         i.atEnd()==false; i++)
82         {
83                 MapEventReceiver* event_receiver = i.getNode()->getKey();
84                 event_receiver->onMapEditEvent(event);
85         }
86 }
87
88 MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
89 {
90         if(m_sector_cache != NULL && p == m_sector_cache_p){
91                 MapSector * sector = m_sector_cache;
92                 return sector;
93         }
94         
95         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
96         
97         if(n == NULL)
98                 return NULL;
99         
100         MapSector *sector = n->getValue();
101         
102         // Cache the last result
103         m_sector_cache_p = p;
104         m_sector_cache = sector;
105
106         return sector;
107 }
108
109 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
110 {
111         return getSectorNoGenerateNoExNoLock(p);
112 }
113
114 MapSector * Map::getSectorNoGenerate(v2s16 p)
115 {
116         MapSector *sector = getSectorNoGenerateNoEx(p);
117         if(sector == NULL)
118                 throw InvalidPositionException();
119         
120         return sector;
121 }
122
123 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
124 {
125         v2s16 p2d(p3d.X, p3d.Z);
126         MapSector * sector = getSectorNoGenerateNoEx(p2d);
127         if(sector == NULL)
128                 return NULL;
129         MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
130         return block;
131 }
132
133 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
134 {       
135         MapBlock *block = getBlockNoCreateNoEx(p3d);
136         if(block == NULL)
137                 throw InvalidPositionException();
138         return block;
139 }
140
141 bool Map::isNodeUnderground(v3s16 p)
142 {
143         v3s16 blockpos = getNodeBlockPos(p);
144         try{
145                 MapBlock * block = getBlockNoCreate(blockpos);
146                 return block->getIsUnderground();
147         }
148         catch(InvalidPositionException &e)
149         {
150                 return false;
151         }
152 }
153
154 bool Map::isValidPosition(v3s16 p)
155 {
156         v3s16 blockpos = getNodeBlockPos(p);
157         MapBlock *block = getBlockNoCreate(blockpos);
158         return (block != NULL);
159 }
160
161 // Returns a CONTENT_IGNORE node if not found
162 MapNode Map::getNodeNoEx(v3s16 p)
163 {
164         v3s16 blockpos = getNodeBlockPos(p);
165         MapBlock *block = getBlockNoCreateNoEx(blockpos);
166         if(block == NULL)
167                 return MapNode(CONTENT_IGNORE);
168         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
169         return block->getNodeNoCheck(relpos);
170 }
171
172 // throws InvalidPositionException if not found
173 MapNode Map::getNode(v3s16 p)
174 {
175         v3s16 blockpos = getNodeBlockPos(p);
176         MapBlock *block = getBlockNoCreateNoEx(blockpos);
177         if(block == NULL)
178                 throw InvalidPositionException();
179         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
180         return block->getNodeNoCheck(relpos);
181 }
182
183 // throws InvalidPositionException if not found
184 void Map::setNode(v3s16 p, MapNode & n)
185 {
186         v3s16 blockpos = getNodeBlockPos(p);
187         MapBlock *block = getBlockNoCreate(blockpos);
188         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
189         block->setNodeNoCheck(relpos, n);
190 }
191
192
193 /*
194         Goes recursively through the neighbours of the node.
195
196         Alters only transparent nodes.
197
198         If the lighting of the neighbour is lower than the lighting of
199         the node was (before changing it to 0 at the step before), the
200         lighting of the neighbour is set to 0 and then the same stuff
201         repeats for the neighbour.
202
203         The ending nodes of the routine are stored in light_sources.
204         This is useful when a light is removed. In such case, this
205         routine can be called for the light node and then again for
206         light_sources to re-light the area without the removed light.
207
208         values of from_nodes are lighting values.
209 */
210 void Map::unspreadLight(enum LightBank bank,
211                 core::map<v3s16, u8> & from_nodes,
212                 core::map<v3s16, bool> & light_sources,
213                 core::map<v3s16, MapBlock*>  & modified_blocks)
214 {
215         v3s16 dirs[6] = {
216                 v3s16(0,0,1), // back
217                 v3s16(0,1,0), // top
218                 v3s16(1,0,0), // right
219                 v3s16(0,0,-1), // front
220                 v3s16(0,-1,0), // bottom
221                 v3s16(-1,0,0), // left
222         };
223         
224         if(from_nodes.size() == 0)
225                 return;
226         
227         u32 blockchangecount = 0;
228
229         core::map<v3s16, u8> unlighted_nodes;
230         core::map<v3s16, u8>::Iterator j;
231         j = from_nodes.getIterator();
232
233         /*
234                 Initialize block cache
235         */
236         v3s16 blockpos_last;
237         MapBlock *block = NULL;
238         // Cache this a bit, too
239         bool block_checked_in_modified = false;
240         
241         for(; j.atEnd() == false; j++)
242         {
243                 v3s16 pos = j.getNode()->getKey();
244                 v3s16 blockpos = getNodeBlockPos(pos);
245                 
246                 // Only fetch a new block if the block position has changed
247                 try{
248                         if(block == NULL || blockpos != blockpos_last){
249                                 block = getBlockNoCreate(blockpos);
250                                 blockpos_last = blockpos;
251
252                                 block_checked_in_modified = false;
253                                 blockchangecount++;
254                         }
255                 }
256                 catch(InvalidPositionException &e)
257                 {
258                         continue;
259                 }
260
261                 if(block->isDummy())
262                         continue;
263
264                 // Calculate relative position in block
265                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
266
267                 // Get node straight from the block
268                 MapNode n = block->getNode(relpos);
269
270                 u8 oldlight = j.getNode()->getValue();
271
272                 // Loop through 6 neighbors
273                 for(u16 i=0; i<6; i++)
274                 {
275                         // Get the position of the neighbor node
276                         v3s16 n2pos = pos + dirs[i];
277
278                         // Get the block where the node is located
279                         v3s16 blockpos = getNodeBlockPos(n2pos);
280
281                         try
282                         {
283                                 // Only fetch a new block if the block position has changed
284                                 try{
285                                         if(block == NULL || blockpos != blockpos_last){
286                                                 block = getBlockNoCreate(blockpos);
287                                                 blockpos_last = blockpos;
288
289                                                 block_checked_in_modified = false;
290                                                 blockchangecount++;
291                                         }
292                                 }
293                                 catch(InvalidPositionException &e)
294                                 {
295                                         continue;
296                                 }
297
298                                 // Calculate relative position in block
299                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
300                                 // Get node straight from the block
301                                 MapNode n2 = block->getNode(relpos);
302
303                                 bool changed = false;
304
305                                 //TODO: Optimize output by optimizing light_sources?
306
307                                 /*
308                                         If the neighbor is dimmer than what was specified
309                                         as oldlight (the light of the previous node)
310                                 */
311                                 if(n2.getLight(bank) < oldlight)
312                                 {
313                                         /*
314                                                 And the neighbor is transparent and it has some light
315                                         */
316                                         if(n2.light_propagates() && n2.getLight(bank) != 0)
317                                         {
318                                                 /*
319                                                         Set light to 0 and add to queue
320                                                 */
321
322                                                 u8 current_light = n2.getLight(bank);
323                                                 n2.setLight(bank, 0);
324                                                 block->setNode(relpos, n2);
325
326                                                 unlighted_nodes.insert(n2pos, current_light);
327                                                 changed = true;
328
329                                                 /*
330                                                         Remove from light_sources if it is there
331                                                         NOTE: This doesn't happen nearly at all
332                                                 */
333                                                 /*if(light_sources.find(n2pos))
334                                                 {
335                                                         std::cout<<"Removed from light_sources"<<std::endl;
336                                                         light_sources.remove(n2pos);
337                                                 }*/
338                                         }
339
340                                         /*// DEBUG
341                                         if(light_sources.find(n2pos) != NULL)
342                                                 light_sources.remove(n2pos);*/
343                                 }
344                                 else{
345                                         light_sources.insert(n2pos, true);
346                                 }
347
348                                 // Add to modified_blocks
349                                 if(changed == true && block_checked_in_modified == false)
350                                 {
351                                         // If the block is not found in modified_blocks, add.
352                                         if(modified_blocks.find(blockpos) == NULL)
353                                         {
354                                                 modified_blocks.insert(blockpos, block);
355                                         }
356                                         block_checked_in_modified = true;
357                                 }
358                         }
359                         catch(InvalidPositionException &e)
360                         {
361                                 continue;
362                         }
363                 }
364         }
365
366         /*dstream<<"unspreadLight(): Changed block "
367                         <<blockchangecount<<" times"
368                         <<" for "<<from_nodes.size()<<" nodes"
369                         <<std::endl;*/
370
371         if(unlighted_nodes.size() > 0)
372                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
373 }
374
375 /*
376         A single-node wrapper of the above
377 */
378 void Map::unLightNeighbors(enum LightBank bank,
379                 v3s16 pos, u8 lightwas,
380                 core::map<v3s16, bool> & light_sources,
381                 core::map<v3s16, MapBlock*>  & modified_blocks)
382 {
383         core::map<v3s16, u8> from_nodes;
384         from_nodes.insert(pos, lightwas);
385
386         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
387 }
388
389 /*
390         Lights neighbors of from_nodes, collects all them and then
391         goes on recursively.
392 */
393 void Map::spreadLight(enum LightBank bank,
394                 core::map<v3s16, bool> & from_nodes,
395                 core::map<v3s16, MapBlock*> & modified_blocks)
396 {
397         const v3s16 dirs[6] = {
398                 v3s16(0,0,1), // back
399                 v3s16(0,1,0), // top
400                 v3s16(1,0,0), // right
401                 v3s16(0,0,-1), // front
402                 v3s16(0,-1,0), // bottom
403                 v3s16(-1,0,0), // left
404         };
405
406         if(from_nodes.size() == 0)
407                 return;
408
409         u32 blockchangecount = 0;
410
411         core::map<v3s16, bool> lighted_nodes;
412         core::map<v3s16, bool>::Iterator j;
413         j = from_nodes.getIterator();
414
415         /*
416                 Initialize block cache
417         */
418         v3s16 blockpos_last;
419         MapBlock *block = NULL;
420         // Cache this a bit, too
421         bool block_checked_in_modified = false;
422
423         for(; j.atEnd() == false; j++)
424         //for(; j != from_nodes.end(); j++)
425         {
426                 v3s16 pos = j.getNode()->getKey();
427                 //v3s16 pos = *j;
428                 //dstream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
429                 v3s16 blockpos = getNodeBlockPos(pos);
430
431                 // Only fetch a new block if the block position has changed
432                 try{
433                         if(block == NULL || blockpos != blockpos_last){
434                                 block = getBlockNoCreate(blockpos);
435                                 blockpos_last = blockpos;
436
437                                 block_checked_in_modified = false;
438                                 blockchangecount++;
439                         }
440                 }
441                 catch(InvalidPositionException &e)
442                 {
443                         continue;
444                 }
445
446                 if(block->isDummy())
447                         continue;
448
449                 // Calculate relative position in block
450                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
451
452                 // Get node straight from the block
453                 MapNode n = block->getNode(relpos);
454
455                 u8 oldlight = n.getLight(bank);
456                 u8 newlight = diminish_light(oldlight);
457
458                 // Loop through 6 neighbors
459                 for(u16 i=0; i<6; i++){
460                         // Get the position of the neighbor node
461                         v3s16 n2pos = pos + dirs[i];
462
463                         // Get the block where the node is located
464                         v3s16 blockpos = getNodeBlockPos(n2pos);
465
466                         try
467                         {
468                                 // Only fetch a new block if the block position has changed
469                                 try{
470                                         if(block == NULL || blockpos != blockpos_last){
471                                                 block = getBlockNoCreate(blockpos);
472                                                 blockpos_last = blockpos;
473
474                                                 block_checked_in_modified = false;
475                                                 blockchangecount++;
476                                         }
477                                 }
478                                 catch(InvalidPositionException &e)
479                                 {
480                                         continue;
481                                 }
482
483                                 // Calculate relative position in block
484                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
485                                 // Get node straight from the block
486                                 MapNode n2 = block->getNode(relpos);
487
488                                 bool changed = false;
489                                 /*
490                                         If the neighbor is brighter than the current node,
491                                         add to list (it will light up this node on its turn)
492                                 */
493                                 if(n2.getLight(bank) > undiminish_light(oldlight))
494                                 {
495                                         lighted_nodes.insert(n2pos, true);
496                                         //lighted_nodes.push_back(n2pos);
497                                         changed = true;
498                                 }
499                                 /*
500                                         If the neighbor is dimmer than how much light this node
501                                         would spread on it, add to list
502                                 */
503                                 if(n2.getLight(bank) < newlight)
504                                 {
505                                         if(n2.light_propagates())
506                                         {
507                                                 n2.setLight(bank, newlight);
508                                                 block->setNode(relpos, n2);
509                                                 lighted_nodes.insert(n2pos, true);
510                                                 //lighted_nodes.push_back(n2pos);
511                                                 changed = true;
512                                         }
513                                 }
514
515                                 // Add to modified_blocks
516                                 if(changed == true && block_checked_in_modified == false)
517                                 {
518                                         // If the block is not found in modified_blocks, add.
519                                         if(modified_blocks.find(blockpos) == NULL)
520                                         {
521                                                 modified_blocks.insert(blockpos, block);
522                                         }
523                                         block_checked_in_modified = true;
524                                 }
525                         }
526                         catch(InvalidPositionException &e)
527                         {
528                                 continue;
529                         }
530                 }
531         }
532
533         /*dstream<<"spreadLight(): Changed block "
534                         <<blockchangecount<<" times"
535                         <<" for "<<from_nodes.size()<<" nodes"
536                         <<std::endl;*/
537
538         if(lighted_nodes.size() > 0)
539                 spreadLight(bank, lighted_nodes, modified_blocks);
540 }
541
542 /*
543         A single-node source variation of the above.
544 */
545 void Map::lightNeighbors(enum LightBank bank,
546                 v3s16 pos,
547                 core::map<v3s16, MapBlock*> & modified_blocks)
548 {
549         core::map<v3s16, bool> from_nodes;
550         from_nodes.insert(pos, true);
551         spreadLight(bank, from_nodes, modified_blocks);
552 }
553
554 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
555 {
556         v3s16 dirs[6] = {
557                 v3s16(0,0,1), // back
558                 v3s16(0,1,0), // top
559                 v3s16(1,0,0), // right
560                 v3s16(0,0,-1), // front
561                 v3s16(0,-1,0), // bottom
562                 v3s16(-1,0,0), // left
563         };
564
565         u8 brightest_light = 0;
566         v3s16 brightest_pos(0,0,0);
567         bool found_something = false;
568
569         // Loop through 6 neighbors
570         for(u16 i=0; i<6; i++){
571                 // Get the position of the neighbor node
572                 v3s16 n2pos = p + dirs[i];
573                 MapNode n2;
574                 try{
575                         n2 = getNode(n2pos);
576                 }
577                 catch(InvalidPositionException &e)
578                 {
579                         continue;
580                 }
581                 if(n2.getLight(bank) > brightest_light || found_something == false){
582                         brightest_light = n2.getLight(bank);
583                         brightest_pos = n2pos;
584                         found_something = true;
585                 }
586         }
587
588         if(found_something == false)
589                 throw InvalidPositionException();
590
591         return brightest_pos;
592 }
593
594 /*
595         Propagates sunlight down from a node.
596         Starting point gets sunlight.
597
598         Returns the lowest y value of where the sunlight went.
599
600         Mud is turned into grass in where the sunlight stops.
601 */
602 s16 Map::propagateSunlight(v3s16 start,
603                 core::map<v3s16, MapBlock*> & modified_blocks)
604 {
605         s16 y = start.Y;
606         for(; ; y--)
607         {
608                 v3s16 pos(start.X, y, start.Z);
609
610                 v3s16 blockpos = getNodeBlockPos(pos);
611                 MapBlock *block;
612                 try{
613                         block = getBlockNoCreate(blockpos);
614                 }
615                 catch(InvalidPositionException &e)
616                 {
617                         break;
618                 }
619
620                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
621                 MapNode n = block->getNode(relpos);
622
623                 if(n.sunlight_propagates())
624                 {
625                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
626                         block->setNode(relpos, n);
627
628                         modified_blocks.insert(blockpos, block);
629                 }
630                 else
631                 {
632                         /*// Turn mud into grass
633                         if(n.getContent() == CONTENT_MUD)
634                         {
635                                 n.setContent(CONTENT_GRASS);
636                                 block->setNode(relpos, n);
637                                 modified_blocks.insert(blockpos, block);
638                         }*/
639
640                         // Sunlight goes no further
641                         break;
642                 }
643         }
644         return y + 1;
645 }
646
647 void Map::updateLighting(enum LightBank bank,
648                 core::map<v3s16, MapBlock*> & a_blocks,
649                 core::map<v3s16, MapBlock*> & modified_blocks)
650 {
651         /*m_dout<<DTIME<<"Map::updateLighting(): "
652                         <<a_blocks.size()<<" blocks."<<std::endl;*/
653
654         //TimeTaker timer("updateLighting");
655
656         // For debugging
657         //bool debug=true;
658         //u32 count_was = modified_blocks.size();
659
660         core::map<v3s16, MapBlock*> blocks_to_update;
661
662         core::map<v3s16, bool> light_sources;
663
664         core::map<v3s16, u8> unlight_from;
665
666         core::map<v3s16, MapBlock*>::Iterator i;
667         i = a_blocks.getIterator();
668         for(; i.atEnd() == false; i++)
669         {
670                 MapBlock *block = i.getNode()->getValue();
671
672                 for(;;)
673                 {
674                         // Don't bother with dummy blocks.
675                         if(block->isDummy())
676                                 break;
677
678                         v3s16 pos = block->getPos();
679                         modified_blocks.insert(pos, block);
680
681                         blocks_to_update.insert(pos, block);
682
683                         /*
684                                 Clear all light from block
685                         */
686                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
687                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
688                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
689                         {
690
691                                 try{
692                                         v3s16 p(x,y,z);
693                                         MapNode n = block->getNode(v3s16(x,y,z));
694                                         u8 oldlight = n.getLight(bank);
695                                         n.setLight(bank, 0);
696                                         block->setNode(v3s16(x,y,z), n);
697
698                                         // Collect borders for unlighting
699                                         if(x==0 || x == MAP_BLOCKSIZE-1
700                                         || y==0 || y == MAP_BLOCKSIZE-1
701                                         || z==0 || z == MAP_BLOCKSIZE-1)
702                                         {
703                                                 v3s16 p_map = p + v3s16(
704                                                                 MAP_BLOCKSIZE*pos.X,
705                                                                 MAP_BLOCKSIZE*pos.Y,
706                                                                 MAP_BLOCKSIZE*pos.Z);
707                                                 unlight_from.insert(p_map, oldlight);
708                                         }
709                                 }
710                                 catch(InvalidPositionException &e)
711                                 {
712                                         /*
713                                                 This would happen when dealing with a
714                                                 dummy block.
715                                         */
716                                         //assert(0);
717                                         dstream<<"updateLighting(): InvalidPositionException"
718                                                         <<std::endl;
719                                 }
720                         }
721
722                         if(bank == LIGHTBANK_DAY)
723                         {
724                                 bool bottom_valid = block->propagateSunlight(light_sources);
725
726                                 // If bottom is valid, we're done.
727                                 if(bottom_valid)
728                                         break;
729                         }
730                         else if(bank == LIGHTBANK_NIGHT)
731                         {
732                                 // For night lighting, sunlight is not propagated
733                                 break;
734                         }
735                         else
736                         {
737                                 // Invalid lighting bank
738                                 assert(0);
739                         }
740
741                         /*dstream<<"Bottom for sunlight-propagated block ("
742                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
743                                         <<std::endl;*/
744
745                         // Bottom sunlight is not valid; get the block and loop to it
746
747                         pos.Y--;
748                         try{
749                                 block = getBlockNoCreate(pos);
750                         }
751                         catch(InvalidPositionException &e)
752                         {
753                                 assert(0);
754                         }
755
756                 }
757         }
758         
759         /*
760                 Enable this to disable proper lighting for speeding up map
761                 generation for testing or whatever
762         */
763 #if 0
764         //if(g_settings.get(""))
765         {
766                 core::map<v3s16, MapBlock*>::Iterator i;
767                 i = blocks_to_update.getIterator();
768                 for(; i.atEnd() == false; i++)
769                 {
770                         MapBlock *block = i.getNode()->getValue();
771                         v3s16 p = block->getPos();
772                         block->setLightingExpired(false);
773                 }
774                 return;
775         }
776 #endif
777
778 #if 0
779         {
780                 TimeTaker timer("unspreadLight");
781                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
782         }
783
784         if(debug)
785         {
786                 u32 diff = modified_blocks.size() - count_was;
787                 count_was = modified_blocks.size();
788                 dstream<<"unspreadLight modified "<<diff<<std::endl;
789         }
790
791         {
792                 TimeTaker timer("spreadLight");
793                 spreadLight(bank, light_sources, modified_blocks);
794         }
795
796         if(debug)
797         {
798                 u32 diff = modified_blocks.size() - count_was;
799                 count_was = modified_blocks.size();
800                 dstream<<"spreadLight modified "<<diff<<std::endl;
801         }
802 #endif
803
804         {
805                 //MapVoxelManipulator vmanip(this);
806
807                 // Make a manual voxel manipulator and load all the blocks
808                 // that touch the requested blocks
809                 ManualMapVoxelManipulator vmanip(this);
810                 core::map<v3s16, MapBlock*>::Iterator i;
811                 i = blocks_to_update.getIterator();
812                 for(; i.atEnd() == false; i++)
813                 {
814                         MapBlock *block = i.getNode()->getValue();
815                         v3s16 p = block->getPos();
816
817                         // Add all surrounding blocks
818                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
819
820                         /*
821                                 Add all surrounding blocks that have up-to-date lighting
822                                 NOTE: This doesn't quite do the job (not everything
823                                           appropriate is lighted)
824                         */
825                         /*for(s16 z=-1; z<=1; z++)
826                         for(s16 y=-1; y<=1; y++)
827                         for(s16 x=-1; x<=1; x++)
828                         {
829                                 v3s16 p(x,y,z);
830                                 MapBlock *block = getBlockNoCreateNoEx(p);
831                                 if(block == NULL)
832                                         continue;
833                                 if(block->isDummy())
834                                         continue;
835                                 if(block->getLightingExpired())
836                                         continue;
837                                 vmanip.initialEmerge(p, p);
838                         }*/
839
840                         // Lighting of block will be updated completely
841                         block->setLightingExpired(false);
842                 }
843
844                 {
845                         //TimeTaker timer("unSpreadLight");
846                         vmanip.unspreadLight(bank, unlight_from, light_sources);
847                 }
848                 {
849                         //TimeTaker timer("spreadLight");
850                         vmanip.spreadLight(bank, light_sources);
851                 }
852                 {
853                         //TimeTaker timer("blitBack");
854                         vmanip.blitBack(modified_blocks);
855                 }
856                 /*dstream<<"emerge_time="<<emerge_time<<std::endl;
857                 emerge_time = 0;*/
858         }
859
860         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
861 }
862
863 void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
864                 core::map<v3s16, MapBlock*> & modified_blocks)
865 {
866         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
867         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
868
869         /*
870                 Update information about whether day and night light differ
871         */
872         for(core::map<v3s16, MapBlock*>::Iterator
873                         i = modified_blocks.getIterator();
874                         i.atEnd() == false; i++)
875         {
876                 MapBlock *block = i.getNode()->getValue();
877                 block->updateDayNightDiff();
878         }
879 }
880
881 /*
882 */
883 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
884                 core::map<v3s16, MapBlock*> &modified_blocks)
885 {
886         /*PrintInfo(m_dout);
887         m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
888                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
889
890         /*
891                 From this node to nodes underneath:
892                 If lighting is sunlight (1.0), unlight neighbours and
893                 set lighting to 0.
894                 Else discontinue.
895         */
896
897         v3s16 toppos = p + v3s16(0,1,0);
898         v3s16 bottompos = p + v3s16(0,-1,0);
899
900         bool node_under_sunlight = true;
901         core::map<v3s16, bool> light_sources;
902
903         /*
904                 If there is a node at top and it doesn't have sunlight,
905                 there has not been any sunlight going down.
906
907                 Otherwise there probably is.
908         */
909         try{
910                 MapNode topnode = getNode(toppos);
911
912                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
913                         node_under_sunlight = false;
914         }
915         catch(InvalidPositionException &e)
916         {
917         }
918
919 #if 0
920         /*
921                 If the new node is solid and there is grass below, change it to mud
922         */
923         if(content_features(n).walkable == true)
924         {
925                 try{
926                         MapNode bottomnode = getNode(bottompos);
927
928                         if(bottomnode.getContent() == CONTENT_GRASS
929                                         || bottomnode.getContent() == CONTENT_GRASS_FOOTSTEPS)
930                         {
931                                 bottomnode.setContent(CONTENT_MUD);
932                                 setNode(bottompos, bottomnode);
933                         }
934                 }
935                 catch(InvalidPositionException &e)
936                 {
937                 }
938         }
939 #endif
940
941 #if 0
942         /*
943                 If the new node is mud and it is under sunlight, change it
944                 to grass
945         */
946         if(n.getContent() == CONTENT_MUD && node_under_sunlight)
947         {
948                 n.setContent(CONTENT_GRASS);
949         }
950 #endif
951
952         /*
953                 Remove all light that has come out of this node
954         */
955
956         enum LightBank banks[] =
957         {
958                 LIGHTBANK_DAY,
959                 LIGHTBANK_NIGHT
960         };
961         for(s32 i=0; i<2; i++)
962         {
963                 enum LightBank bank = banks[i];
964
965                 u8 lightwas = getNode(p).getLight(bank);
966
967                 // Add the block of the added node to modified_blocks
968                 v3s16 blockpos = getNodeBlockPos(p);
969                 MapBlock * block = getBlockNoCreate(blockpos);
970                 assert(block != NULL);
971                 modified_blocks.insert(blockpos, block);
972
973                 assert(isValidPosition(p));
974
975                 // Unlight neighbours of node.
976                 // This means setting light of all consequent dimmer nodes
977                 // to 0.
978                 // This also collects the nodes at the border which will spread
979                 // light again into this.
980                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
981
982                 n.setLight(bank, 0);
983         }
984
985         /*
986                 If node lets sunlight through and is under sunlight, it has
987                 sunlight too.
988         */
989         if(node_under_sunlight && content_features(n).sunlight_propagates)
990         {
991                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
992         }
993
994         /*
995                 Set the node on the map
996         */
997
998         setNode(p, n);
999
1000         /*
1001                 Add intial metadata
1002         */
1003
1004         NodeMetadata *meta_proto = content_features(n).initial_metadata;
1005         if(meta_proto)
1006         {
1007                 NodeMetadata *meta = meta_proto->clone();
1008                 setNodeMetadata(p, meta);
1009         }
1010
1011         /*
1012                 If node is under sunlight and doesn't let sunlight through,
1013                 take all sunlighted nodes under it and clear light from them
1014                 and from where the light has been spread.
1015                 TODO: This could be optimized by mass-unlighting instead
1016                           of looping
1017         */
1018         if(node_under_sunlight && !content_features(n).sunlight_propagates)
1019         {
1020                 s16 y = p.Y - 1;
1021                 for(;; y--){
1022                         //m_dout<<DTIME<<"y="<<y<<std::endl;
1023                         v3s16 n2pos(p.X, y, p.Z);
1024
1025                         MapNode n2;
1026                         try{
1027                                 n2 = getNode(n2pos);
1028                         }
1029                         catch(InvalidPositionException &e)
1030                         {
1031                                 break;
1032                         }
1033
1034                         if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
1035                         {
1036                                 unLightNeighbors(LIGHTBANK_DAY,
1037                                                 n2pos, n2.getLight(LIGHTBANK_DAY),
1038                                                 light_sources, modified_blocks);
1039                                 n2.setLight(LIGHTBANK_DAY, 0);
1040                                 setNode(n2pos, n2);
1041                         }
1042                         else
1043                                 break;
1044                 }
1045         }
1046
1047         for(s32 i=0; i<2; i++)
1048         {
1049                 enum LightBank bank = banks[i];
1050
1051                 /*
1052                         Spread light from all nodes that might be capable of doing so
1053                 */
1054                 spreadLight(bank, light_sources, modified_blocks);
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                 Add neighboring liquid nodes and the node itself if it is
1070                 liquid (=water node was added) to transform queue.
1071         */
1072         v3s16 dirs[7] = {
1073                 v3s16(0,0,0), // self
1074                 v3s16(0,0,1), // back
1075                 v3s16(0,1,0), // top
1076                 v3s16(1,0,0), // right
1077                 v3s16(0,0,-1), // front
1078                 v3s16(0,-1,0), // bottom
1079                 v3s16(-1,0,0), // left
1080         };
1081         for(u16 i=0; i<7; i++)
1082         {
1083                 try
1084                 {
1085
1086                 v3s16 p2 = p + dirs[i];
1087
1088                 MapNode n2 = getNode(p2);
1089                 if(content_liquid(n2.getContent()) || n2.getContent() == CONTENT_AIR)
1090                 {
1091                         m_transforming_liquid.push_back(p2);
1092                 }
1093
1094                 }catch(InvalidPositionException &e)
1095                 {
1096                 }
1097         }
1098 }
1099
1100 /*
1101 */
1102 void Map::removeNodeAndUpdate(v3s16 p,
1103                 core::map<v3s16, MapBlock*> &modified_blocks)
1104 {
1105         /*PrintInfo(m_dout);
1106         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1107                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1108
1109         bool node_under_sunlight = true;
1110
1111         v3s16 toppos = p + v3s16(0,1,0);
1112
1113         // Node will be replaced with this
1114         content_t replace_material = CONTENT_AIR;
1115
1116         /*
1117                 If there is a node at top and it doesn't have sunlight,
1118                 there will be no sunlight going down.
1119         */
1120         try{
1121                 MapNode topnode = getNode(toppos);
1122
1123                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1124                         node_under_sunlight = false;
1125         }
1126         catch(InvalidPositionException &e)
1127         {
1128         }
1129
1130         core::map<v3s16, bool> light_sources;
1131
1132         enum LightBank banks[] =
1133         {
1134                 LIGHTBANK_DAY,
1135                 LIGHTBANK_NIGHT
1136         };
1137         for(s32 i=0; i<2; i++)
1138         {
1139                 enum LightBank bank = banks[i];
1140
1141                 /*
1142                         Unlight neighbors (in case the node is a light source)
1143                 */
1144                 unLightNeighbors(bank, p,
1145                                 getNode(p).getLight(bank),
1146                                 light_sources, modified_blocks);
1147         }
1148
1149         /*
1150                 Remove node metadata
1151         */
1152
1153         removeNodeMetadata(p);
1154
1155         /*
1156                 Remove the node.
1157                 This also clears the lighting.
1158         */
1159
1160         MapNode n;
1161         n.setContent(replace_material);
1162         setNode(p, n);
1163
1164         for(s32 i=0; i<2; i++)
1165         {
1166                 enum LightBank bank = banks[i];
1167
1168                 /*
1169                         Recalculate lighting
1170                 */
1171                 spreadLight(bank, light_sources, modified_blocks);
1172         }
1173
1174         // Add the block of the removed node to modified_blocks
1175         v3s16 blockpos = getNodeBlockPos(p);
1176         MapBlock * block = getBlockNoCreate(blockpos);
1177         assert(block != NULL);
1178         modified_blocks.insert(blockpos, block);
1179
1180         /*
1181                 If the removed node was under sunlight, propagate the
1182                 sunlight down from it and then light all neighbors
1183                 of the propagated blocks.
1184         */
1185         if(node_under_sunlight)
1186         {
1187                 s16 ybottom = propagateSunlight(p, modified_blocks);
1188                 /*m_dout<<DTIME<<"Node was under sunlight. "
1189                                 "Propagating sunlight";
1190                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1191                 s16 y = p.Y;
1192                 for(; y >= ybottom; y--)
1193                 {
1194                         v3s16 p2(p.X, y, p.Z);
1195                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1196                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1197                                         <<std::endl;*/
1198                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1199                 }
1200         }
1201         else
1202         {
1203                 // Set the lighting of this node to 0
1204                 // TODO: Is this needed? Lighting is cleared up there already.
1205                 try{
1206                         MapNode n = getNode(p);
1207                         n.setLight(LIGHTBANK_DAY, 0);
1208                         setNode(p, n);
1209                 }
1210                 catch(InvalidPositionException &e)
1211                 {
1212                         assert(0);
1213                 }
1214         }
1215
1216         for(s32 i=0; i<2; i++)
1217         {
1218                 enum LightBank bank = banks[i];
1219
1220                 // Get the brightest neighbour node and propagate light from it
1221                 v3s16 n2p = getBrightestNeighbour(bank, p);
1222                 try{
1223                         MapNode n2 = getNode(n2p);
1224                         lightNeighbors(bank, n2p, modified_blocks);
1225                 }
1226                 catch(InvalidPositionException &e)
1227                 {
1228                 }
1229         }
1230
1231         /*
1232                 Update information about whether day and night light differ
1233         */
1234         for(core::map<v3s16, MapBlock*>::Iterator
1235                         i = modified_blocks.getIterator();
1236                         i.atEnd() == false; i++)
1237         {
1238                 MapBlock *block = i.getNode()->getValue();
1239                 block->updateDayNightDiff();
1240         }
1241
1242         /*
1243                 Add neighboring liquid nodes and this node to transform queue.
1244                 (it's vital for the node itself to get updated last.)
1245         */
1246         v3s16 dirs[7] = {
1247                 v3s16(0,0,1), // back
1248                 v3s16(0,1,0), // top
1249                 v3s16(1,0,0), // right
1250                 v3s16(0,0,-1), // front
1251                 v3s16(0,-1,0), // bottom
1252                 v3s16(-1,0,0), // left
1253                 v3s16(0,0,0), // self
1254         };
1255         for(u16 i=0; i<7; i++)
1256         {
1257                 try
1258                 {
1259
1260                 v3s16 p2 = p + dirs[i];
1261
1262                 MapNode n2 = getNode(p2);
1263                 if(content_liquid(n2.getContent()) || n2.getContent() == CONTENT_AIR)
1264                 {
1265                         m_transforming_liquid.push_back(p2);
1266                 }
1267
1268                 }catch(InvalidPositionException &e)
1269                 {
1270                 }
1271         }
1272 }
1273
1274 bool Map::addNodeWithEvent(v3s16 p, MapNode n)
1275 {
1276         MapEditEvent event;
1277         event.type = MEET_ADDNODE;
1278         event.p = p;
1279         event.n = n;
1280
1281         bool succeeded = true;
1282         try{
1283                 core::map<v3s16, MapBlock*> modified_blocks;
1284                 addNodeAndUpdate(p, n, modified_blocks);
1285
1286                 // Copy modified_blocks to event
1287                 for(core::map<v3s16, MapBlock*>::Iterator
1288                                 i = modified_blocks.getIterator();
1289                                 i.atEnd()==false; i++)
1290                 {
1291                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1292                 }
1293         }
1294         catch(InvalidPositionException &e){
1295                 succeeded = false;
1296         }
1297
1298         dispatchEvent(&event);
1299
1300         return succeeded;
1301 }
1302
1303 bool Map::removeNodeWithEvent(v3s16 p)
1304 {
1305         MapEditEvent event;
1306         event.type = MEET_REMOVENODE;
1307         event.p = p;
1308
1309         bool succeeded = true;
1310         try{
1311                 core::map<v3s16, MapBlock*> modified_blocks;
1312                 removeNodeAndUpdate(p, modified_blocks);
1313
1314                 // Copy modified_blocks to event
1315                 for(core::map<v3s16, MapBlock*>::Iterator
1316                                 i = modified_blocks.getIterator();
1317                                 i.atEnd()==false; i++)
1318                 {
1319                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1320                 }
1321         }
1322         catch(InvalidPositionException &e){
1323                 succeeded = false;
1324         }
1325
1326         dispatchEvent(&event);
1327
1328         return succeeded;
1329 }
1330
1331 bool Map::dayNightDiffed(v3s16 blockpos)
1332 {
1333         try{
1334                 v3s16 p = blockpos + v3s16(0,0,0);
1335                 MapBlock *b = getBlockNoCreate(p);
1336                 if(b->dayNightDiffed())
1337                         return true;
1338         }
1339         catch(InvalidPositionException &e){}
1340         // Leading edges
1341         try{
1342                 v3s16 p = blockpos + v3s16(-1,0,0);
1343                 MapBlock *b = getBlockNoCreate(p);
1344                 if(b->dayNightDiffed())
1345                         return true;
1346         }
1347         catch(InvalidPositionException &e){}
1348         try{
1349                 v3s16 p = blockpos + v3s16(0,-1,0);
1350                 MapBlock *b = getBlockNoCreate(p);
1351                 if(b->dayNightDiffed())
1352                         return true;
1353         }
1354         catch(InvalidPositionException &e){}
1355         try{
1356                 v3s16 p = blockpos + v3s16(0,0,-1);
1357                 MapBlock *b = getBlockNoCreate(p);
1358                 if(b->dayNightDiffed())
1359                         return true;
1360         }
1361         catch(InvalidPositionException &e){}
1362         // Trailing edges
1363         try{
1364                 v3s16 p = blockpos + v3s16(1,0,0);
1365                 MapBlock *b = getBlockNoCreate(p);
1366                 if(b->dayNightDiffed())
1367                         return true;
1368         }
1369         catch(InvalidPositionException &e){}
1370         try{
1371                 v3s16 p = blockpos + v3s16(0,1,0);
1372                 MapBlock *b = getBlockNoCreate(p);
1373                 if(b->dayNightDiffed())
1374                         return true;
1375         }
1376         catch(InvalidPositionException &e){}
1377         try{
1378                 v3s16 p = blockpos + v3s16(0,0,1);
1379                 MapBlock *b = getBlockNoCreate(p);
1380                 if(b->dayNightDiffed())
1381                         return true;
1382         }
1383         catch(InvalidPositionException &e){}
1384
1385         return false;
1386 }
1387
1388 /*
1389         Updates usage timers
1390 */
1391 void Map::timerUpdate(float dtime, float unload_timeout,
1392                 core::list<v3s16> *unloaded_blocks)
1393 {
1394         bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
1395         
1396         core::list<v2s16> sector_deletion_queue;
1397         u32 deleted_blocks_count = 0;
1398         u32 saved_blocks_count = 0;
1399
1400         core::map<v2s16, MapSector*>::Iterator si;
1401
1402         si = m_sectors.getIterator();
1403         for(; si.atEnd() == false; si++)
1404         {
1405                 MapSector *sector = si.getNode()->getValue();
1406
1407                 bool all_blocks_deleted = true;
1408
1409                 core::list<MapBlock*> blocks;
1410                 sector->getBlocks(blocks);
1411                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1412                                 i != blocks.end(); i++)
1413                 {
1414                         MapBlock *block = (*i);
1415                         
1416                         block->incrementUsageTimer(dtime);
1417                         
1418                         if(block->getUsageTimer() > unload_timeout)
1419                         {
1420                                 v3s16 p = block->getPos();
1421
1422                                 // Save if modified
1423                                 if(block->getModified() != MOD_STATE_CLEAN
1424                                                 && save_before_unloading)
1425                                 {
1426                                         saveBlock(block);
1427                                         saved_blocks_count++;
1428                                 }
1429
1430                                 // Delete from memory
1431                                 sector->deleteBlock(block);
1432
1433                                 if(unloaded_blocks)
1434                                         unloaded_blocks->push_back(p);
1435
1436                                 deleted_blocks_count++;
1437                         }
1438                         else
1439                         {
1440                                 all_blocks_deleted = false;
1441                         }
1442                 }
1443
1444                 if(all_blocks_deleted)
1445                 {
1446                         sector_deletion_queue.push_back(si.getNode()->getKey());
1447                 }
1448         }
1449         
1450         // Finally delete the empty sectors
1451         deleteSectors(sector_deletion_queue);
1452         
1453         if(deleted_blocks_count != 0)
1454         {
1455                 PrintInfo(dstream); // ServerMap/ClientMap:
1456                 dstream<<"Unloaded "<<deleted_blocks_count
1457                                 <<" blocks from memory";
1458                 if(save_before_unloading)
1459                         dstream<<", of which "<<saved_blocks_count<<" were written";
1460                 dstream<<"."<<std::endl;
1461         }
1462 }
1463
1464 void Map::deleteSectors(core::list<v2s16> &list)
1465 {
1466         core::list<v2s16>::Iterator j;
1467         for(j=list.begin(); j!=list.end(); j++)
1468         {
1469                 MapSector *sector = m_sectors[*j];
1470                 // If sector is in sector cache, remove it from there
1471                 if(m_sector_cache == sector)
1472                         m_sector_cache = NULL;
1473                 // Remove from map and delete
1474                 m_sectors.remove(*j);
1475                 delete sector;
1476         }
1477 }
1478
1479 #if 0
1480 void Map::unloadUnusedData(float timeout,
1481                 core::list<v3s16> *deleted_blocks)
1482 {
1483         core::list<v2s16> sector_deletion_queue;
1484         u32 deleted_blocks_count = 0;
1485         u32 saved_blocks_count = 0;
1486
1487         core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
1488         for(; si.atEnd() == false; si++)
1489         {
1490                 MapSector *sector = si.getNode()->getValue();
1491
1492                 bool all_blocks_deleted = true;
1493
1494                 core::list<MapBlock*> blocks;
1495                 sector->getBlocks(blocks);
1496                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1497                                 i != blocks.end(); i++)
1498                 {
1499                         MapBlock *block = (*i);
1500                         
1501                         if(block->getUsageTimer() > timeout)
1502                         {
1503                                 // Save if modified
1504                                 if(block->getModified() != MOD_STATE_CLEAN)
1505                                 {
1506                                         saveBlock(block);
1507                                         saved_blocks_count++;
1508                                 }
1509                                 // Delete from memory
1510                                 sector->deleteBlock(block);
1511                                 deleted_blocks_count++;
1512                         }
1513                         else
1514                         {
1515                                 all_blocks_deleted = false;
1516                         }
1517                 }
1518
1519                 if(all_blocks_deleted)
1520                 {
1521                         sector_deletion_queue.push_back(si.getNode()->getKey());
1522                 }
1523         }
1524
1525         deleteSectors(sector_deletion_queue);
1526
1527         dstream<<"Map: Unloaded "<<deleted_blocks_count<<" blocks from memory"
1528                         <<", of which "<<saved_blocks_count<<" were wr."
1529                         <<std::endl;
1530
1531         //return sector_deletion_queue.getSize();
1532         //return deleted_blocks_count;
1533 }
1534 #endif
1535
1536 void Map::PrintInfo(std::ostream &out)
1537 {
1538         out<<"Map: ";
1539 }
1540
1541 #define WATER_DROP_BOOST 4
1542
1543 enum NeighborType {
1544         NEIGHBOR_UPPER,
1545         NEIGHBOR_SAME_LEVEL,
1546         NEIGHBOR_LOWER
1547 };
1548 struct NodeNeighbor {
1549         MapNode n;
1550         NeighborType t;
1551         v3s16 p;
1552 };
1553
1554 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1555 {
1556         DSTACK(__FUNCTION_NAME);
1557         //TimeTaker timer("transformLiquids()");
1558
1559         u32 loopcount = 0;
1560         u32 initial_size = m_transforming_liquid.size();
1561
1562         /*if(initial_size != 0)
1563                 dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1564
1565         // list of nodes that due to viscosity have not reached their max level height
1566         UniqueQueue<v3s16> must_reflow;
1567         
1568         // List of MapBlocks that will require a lighting update (due to lava)
1569         core::map<v3s16, MapBlock*> lighting_modified_blocks;
1570
1571         while(m_transforming_liquid.size() != 0)
1572         {
1573                 // This should be done here so that it is done when continue is used
1574                 if(loopcount >= initial_size * 3)
1575                         break;
1576                 loopcount++;
1577
1578                 /*
1579                         Get a queued transforming liquid node
1580                 */
1581                 v3s16 p0 = m_transforming_liquid.pop_front();
1582
1583                 MapNode n0 = getNodeNoEx(p0);
1584
1585                 /*
1586                         Collect information about current node
1587                  */
1588                 s8 liquid_level = -1;
1589                 u8 liquid_kind = CONTENT_IGNORE;
1590                 LiquidType liquid_type = content_features(n0.getContent()).liquid_type;
1591                 switch (liquid_type) {
1592                         case LIQUID_SOURCE:
1593                                 liquid_level = LIQUID_LEVEL_SOURCE;
1594                                 liquid_kind = content_features(n0.getContent()).liquid_alternative_flowing;
1595                                 break;
1596                         case LIQUID_FLOWING:
1597                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
1598                                 liquid_kind = n0.getContent();
1599                                 break;
1600                         case LIQUID_NONE:
1601                                 // if this is an air node, it *could* be transformed into a liquid. otherwise,
1602                                 // continue with the next node.
1603                                 if (n0.getContent() != CONTENT_AIR)
1604                                         continue;
1605                                 liquid_kind = CONTENT_AIR;
1606                                 break;
1607                 }
1608
1609                 /*
1610                         Collect information about the environment
1611                  */
1612                 const v3s16 *dirs = g_6dirs;
1613                 NodeNeighbor sources[6]; // surrounding sources
1614                 int num_sources = 0;
1615                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
1616                 int num_flows = 0;
1617                 NodeNeighbor airs[6]; // surrounding air
1618                 int num_airs = 0;
1619                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
1620                 int num_neutrals = 0;
1621                 bool flowing_down = false;
1622                 for (u16 i = 0; i < 6; i++) {
1623                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1624                         switch (i) {
1625                                 case 1:
1626                                         nt = NEIGHBOR_UPPER;
1627                                         break;
1628                                 case 4:
1629                                         nt = NEIGHBOR_LOWER;
1630                                         break;
1631                         }
1632                         v3s16 npos = p0 + dirs[i];
1633                         NodeNeighbor nb = {getNodeNoEx(npos), nt, npos};
1634                         switch (content_features(nb.n.getContent()).liquid_type) {
1635                                 case LIQUID_NONE:
1636                                         if (nb.n.getContent() == CONTENT_AIR) {
1637                                                 airs[num_airs++] = nb;
1638                                                 // if the current node is a water source the neighbor
1639                                                 // should be enqueded for transformation regardless of whether the
1640                                                 // current node changes or not.
1641                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
1642                                                         m_transforming_liquid.push_back(npos);
1643                                                 // if the current node happens to be a flowing node, it will start to flow down here.
1644                                                 if (nb.t == NEIGHBOR_LOWER) {
1645                                                         flowing_down = true;
1646                                                 }
1647                                         } else {
1648                                                 neutrals[num_neutrals++] = nb;
1649                                         }
1650                                         break;
1651                                 case LIQUID_SOURCE:
1652                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter 
1653                                         if (liquid_kind == CONTENT_AIR)
1654                                                 liquid_kind = content_features(nb.n.getContent()).liquid_alternative_flowing;
1655                                         if (content_features(nb.n.getContent()).liquid_alternative_flowing !=liquid_kind) {
1656                                                 neutrals[num_neutrals++] = nb;
1657                                         } else {
1658                                                 sources[num_sources++] = nb;
1659                                         }
1660                                         break;
1661                                 case LIQUID_FLOWING:
1662                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1663                                         if (liquid_kind == CONTENT_AIR)
1664                                                 liquid_kind = content_features(nb.n.getContent()).liquid_alternative_flowing;
1665                                         if (content_features(nb.n.getContent()).liquid_alternative_flowing != liquid_kind) {
1666                                                 neutrals[num_neutrals++] = nb;
1667                                         } else {
1668                                                 flows[num_flows++] = nb;
1669                                                 if (nb.t == NEIGHBOR_LOWER)
1670                                                         flowing_down = true;
1671                                         }
1672                                         break;
1673                         }
1674                 }
1675
1676                 /*
1677                         decide on the type (and possibly level) of the current node
1678                  */
1679                 content_t new_node_content;
1680                 s8 new_node_level = -1;
1681                 s8 max_node_level = -1;
1682                 if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
1683                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1684                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1685                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1686                         new_node_content = content_features(liquid_kind).liquid_alternative_source;
1687                 } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
1688                         // liquid_kind is set properly, see above
1689                         new_node_content = liquid_kind;
1690                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
1691                 } else {
1692                         // no surrounding sources, so get the maximum level that can flow into this node
1693                         for (u16 i = 0; i < num_flows; i++) {
1694                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1695                                 switch (flows[i].t) {
1696                                         case NEIGHBOR_UPPER:
1697                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
1698                                                         max_node_level = LIQUID_LEVEL_MAX;
1699                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1700                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
1701                                                 }
1702                                                 break;
1703                                         case NEIGHBOR_LOWER:
1704                                                 break;
1705                                         case NEIGHBOR_SAME_LEVEL:
1706                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1707                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
1708                                                         max_node_level = nb_liquid_level - 1;
1709                                                 }
1710                                                 break;
1711                                 }
1712                         }
1713
1714                         u8 viscosity = content_features(liquid_kind).liquid_viscosity;
1715                         if (viscosity > 1 && max_node_level != liquid_level) {
1716                                 // amount to gain, limited by viscosity
1717                                 // must be at least 1 in absolute value
1718                                 s8 level_inc = max_node_level - liquid_level;
1719                                 if (level_inc < -viscosity || level_inc > viscosity)
1720                                         new_node_level = liquid_level + level_inc/viscosity;
1721                                 else if (level_inc < 0)
1722                                         new_node_level = liquid_level - 1;
1723                                 else if (level_inc > 0)
1724                                         new_node_level = liquid_level + 1;
1725                                 if (new_node_level != max_node_level)
1726                                         must_reflow.push_back(p0);
1727                         } else
1728                                 new_node_level = max_node_level;
1729
1730                         if (new_node_level >= 0)
1731                                 new_node_content = liquid_kind;
1732                         else
1733                                 new_node_content = CONTENT_AIR;
1734
1735                 }
1736
1737                 /*
1738                         check if anything has changed. if not, just continue with the next node.
1739                  */
1740                 if (new_node_content == n0.getContent() && (content_features(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1741                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1742                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1743                                                                                  == flowing_down)))
1744                         continue;
1745
1746
1747                 /*
1748                         update the current node
1749                  */
1750                 bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1751                 if (content_features(new_node_content).liquid_type == LIQUID_FLOWING) {
1752                         // set level to last 3 bits, flowing down bit to 4th bit
1753                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1754                 } else {
1755                         // set the liquid level and flow bit to 0
1756                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1757                 }
1758                 n0.setContent(new_node_content);
1759                 setNode(p0, n0);
1760                 v3s16 blockpos = getNodeBlockPos(p0);
1761                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1762                 if(block != NULL) {
1763                         modified_blocks.insert(blockpos, block);
1764                         // If node emits light, MapBlock requires lighting update
1765                         if(content_features(n0).light_source != 0)
1766                                 lighting_modified_blocks[block->getPos()] = block;
1767                 }
1768
1769                 /*
1770                         enqueue neighbors for update if neccessary
1771                  */
1772                 switch (content_features(n0.getContent()).liquid_type) {
1773                         case LIQUID_SOURCE:
1774                         case LIQUID_FLOWING:
1775                                 // make sure source flows into all neighboring nodes
1776                                 for (u16 i = 0; i < num_flows; i++)
1777                                         if (flows[i].t != NEIGHBOR_UPPER)
1778                                                 m_transforming_liquid.push_back(flows[i].p);
1779                                 for (u16 i = 0; i < num_airs; i++)
1780                                         if (airs[i].t != NEIGHBOR_UPPER)
1781                                                 m_transforming_liquid.push_back(airs[i].p);
1782                                 break;
1783                         case LIQUID_NONE:
1784                                 // this flow has turned to air; neighboring flows might need to do the same
1785                                 for (u16 i = 0; i < num_flows; i++)
1786                                         m_transforming_liquid.push_back(flows[i].p);
1787                                 break;
1788                 }
1789         }
1790         //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1791         while (must_reflow.size() > 0)
1792                 m_transforming_liquid.push_back(must_reflow.pop_front());
1793         updateLighting(lighting_modified_blocks, modified_blocks);
1794 }
1795
1796 NodeMetadata* Map::getNodeMetadata(v3s16 p)
1797 {
1798         v3s16 blockpos = getNodeBlockPos(p);
1799         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1800         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1801         if(block == NULL)
1802         {
1803                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1804                                 <<std::endl;
1805                 return NULL;
1806         }
1807         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1808         return meta;
1809 }
1810
1811 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1812 {
1813         v3s16 blockpos = getNodeBlockPos(p);
1814         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1815         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1816         if(block == NULL)
1817         {
1818                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1819                                 <<std::endl;
1820                 return;
1821         }
1822         block->m_node_metadata.set(p_rel, meta);
1823 }
1824
1825 void Map::removeNodeMetadata(v3s16 p)
1826 {
1827         v3s16 blockpos = getNodeBlockPos(p);
1828         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1829         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1830         if(block == NULL)
1831         {
1832                 dstream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1833                                 <<std::endl;
1834                 return;
1835         }
1836         block->m_node_metadata.remove(p_rel);
1837 }
1838
1839 void Map::nodeMetadataStep(float dtime,
1840                 core::map<v3s16, MapBlock*> &changed_blocks)
1841 {
1842         /*
1843                 NOTE:
1844                 Currently there is no way to ensure that all the necessary
1845                 blocks are loaded when this is run. (They might get unloaded)
1846                 NOTE: ^- Actually, that might not be so. In a quick test it
1847                 reloaded a block with a furnace when I walked back to it from
1848                 a distance.
1849         */
1850         core::map<v2s16, MapSector*>::Iterator si;
1851         si = m_sectors.getIterator();
1852         for(; si.atEnd() == false; si++)
1853         {
1854                 MapSector *sector = si.getNode()->getValue();
1855                 core::list< MapBlock * > sectorblocks;
1856                 sector->getBlocks(sectorblocks);
1857                 core::list< MapBlock * >::Iterator i;
1858                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1859                 {
1860                         MapBlock *block = *i;
1861                         bool changed = block->m_node_metadata.step(dtime);
1862                         if(changed)
1863                                 changed_blocks[block->getPos()] = block;
1864                 }
1865         }
1866 }
1867
1868 /*
1869         ServerMap
1870 */
1871
1872 ServerMap::ServerMap(std::string savedir):
1873         Map(dout_server),
1874         m_seed(0),
1875         m_map_metadata_changed(true)
1876 {
1877         dstream<<__FUNCTION_NAME<<std::endl;
1878
1879         //m_chunksize = 8; // Takes a few seconds
1880
1881         m_seed = (((u64)(myrand()%0xffff)<<0)
1882                         + ((u64)(myrand()%0xffff)<<16)
1883                         + ((u64)(myrand()%0xffff)<<32)
1884                         + ((u64)(myrand()%0xffff)<<48));
1885
1886         /*
1887                 Experimental and debug stuff
1888         */
1889
1890         {
1891         }
1892
1893         /*
1894                 Try to load map; if not found, create a new one.
1895         */
1896
1897         m_savedir = savedir;
1898         m_map_saving_enabled = false;
1899
1900         try
1901         {
1902                 // If directory exists, check contents and load if possible
1903                 if(fs::PathExists(m_savedir))
1904                 {
1905                         // If directory is empty, it is safe to save into it.
1906                         if(fs::GetDirListing(m_savedir).size() == 0)
1907                         {
1908                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1909                                                 <<std::endl;
1910                                 m_map_saving_enabled = true;
1911                         }
1912                         else
1913                         {
1914                                 try{
1915                                         // Load map metadata (seed, chunksize)
1916                                         loadMapMeta();
1917                                 }
1918                                 catch(FileNotGoodException &e){
1919                                         dstream<<DTIME<<"WARNING: Could not load map metadata"
1920                                                         //<<" Disabling chunk-based generator."
1921                                                         <<std::endl;
1922                                         //m_chunksize = 0;
1923                                 }
1924
1925                                 /*try{
1926                                         // Load chunk metadata
1927                                         loadChunkMeta();
1928                                 }
1929                                 catch(FileNotGoodException &e){
1930                                         dstream<<DTIME<<"WARNING: Could not load chunk metadata."
1931                                                         <<" Disabling chunk-based generator."
1932                                                         <<std::endl;
1933                                         m_chunksize = 0;
1934                                 }*/
1935
1936                                 /*dstream<<DTIME<<"Server: Successfully loaded chunk "
1937                                                 "metadata and sector (0,0) from "<<savedir<<
1938                                                 ", assuming valid save directory."
1939                                                 <<std::endl;*/
1940
1941                                 dstream<<DTIME<<"INFO: Server: Successfully loaded map "
1942                                                 <<"and chunk metadata from "<<savedir
1943                                                 <<", assuming valid save directory."
1944                                                 <<std::endl;
1945
1946                                 m_map_saving_enabled = true;
1947                                 // Map loaded, not creating new one
1948                                 return;
1949                         }
1950                 }
1951                 // If directory doesn't exist, it is safe to save to it
1952                 else{
1953                         m_map_saving_enabled = true;
1954                 }
1955         }
1956         catch(std::exception &e)
1957         {
1958                 dstream<<DTIME<<"WARNING: Server: Failed to load map from "<<savedir
1959                                 <<", exception: "<<e.what()<<std::endl;
1960                 dstream<<"Please remove the map or fix it."<<std::endl;
1961                 dstream<<"WARNING: Map saving will be disabled."<<std::endl;
1962         }
1963
1964         dstream<<DTIME<<"INFO: Initializing new map."<<std::endl;
1965
1966         // Create zero sector
1967         emergeSector(v2s16(0,0));
1968
1969         // Initially write whole map
1970         save(false);
1971 }
1972
1973 ServerMap::~ServerMap()
1974 {
1975         dstream<<__FUNCTION_NAME<<std::endl;
1976
1977         try
1978         {
1979                 if(m_map_saving_enabled)
1980                 {
1981                         // Save only changed parts
1982                         save(true);
1983                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1984                 }
1985                 else
1986                 {
1987                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1988                 }
1989         }
1990         catch(std::exception &e)
1991         {
1992                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1993                                 <<", exception: "<<e.what()<<std::endl;
1994         }
1995
1996 #if 0
1997         /*
1998                 Free all MapChunks
1999         */
2000         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2001         for(; i.atEnd() == false; i++)
2002         {
2003                 MapChunk *chunk = i.getNode()->getValue();
2004                 delete chunk;
2005         }
2006 #endif
2007 }
2008
2009 void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
2010 {
2011         bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
2012         if(enable_mapgen_debug_info)
2013                 dstream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2014                                 <<blockpos.Z<<")"<<std::endl;
2015         
2016         // Do nothing if not inside limits (+-1 because of neighbors)
2017         if(blockpos_over_limit(blockpos - v3s16(1,1,1)) ||
2018                 blockpos_over_limit(blockpos + v3s16(1,1,1)))
2019         {
2020                 data->no_op = true;
2021                 return;
2022         }
2023         
2024         data->no_op = false;
2025         data->seed = m_seed;
2026         data->blockpos = blockpos;
2027
2028         /*
2029                 Create the whole area of this and the neighboring blocks
2030         */
2031         {
2032                 //TimeTaker timer("initBlockMake() create area");
2033                 
2034                 for(s16 x=-1; x<=1; x++)
2035                 for(s16 z=-1; z<=1; z++)
2036                 {
2037                         v2s16 sectorpos(blockpos.X+x, blockpos.Z+z);
2038                         // Sector metadata is loaded from disk if not already loaded.
2039                         ServerMapSector *sector = createSector(sectorpos);
2040                         assert(sector);
2041
2042                         for(s16 y=-1; y<=1; y++)
2043                         {
2044                                 v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z);
2045                                 //MapBlock *block = createBlock(p);
2046                                 // 1) get from memory, 2) load from disk
2047                                 MapBlock *block = emergeBlock(p, false);
2048                                 // 3) create a blank one
2049                                 if(block == NULL)
2050                                 {
2051                                         block = createBlock(p);
2052
2053                                         /*
2054                                                 Block gets sunlight if this is true.
2055
2056                                                 Refer to the map generator heuristics.
2057                                         */
2058                                         bool ug = mapgen::block_is_underground(data->seed, p);
2059                                         block->setIsUnderground(ug);
2060                                 }
2061
2062                                 // Lighting will not be valid after make_chunk is called
2063                                 block->setLightingExpired(true);
2064                                 // Lighting will be calculated
2065                                 //block->setLightingExpired(false);
2066                         }
2067                 }
2068         }
2069         
2070         /*
2071                 Now we have a big empty area.
2072
2073                 Make a ManualMapVoxelManipulator that contains this and the
2074                 neighboring blocks
2075         */
2076         
2077         // The area that contains this block and it's neighbors
2078         v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
2079         v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
2080         
2081         data->vmanip = new ManualMapVoxelManipulator(this);
2082         //data->vmanip->setMap(this);
2083
2084         // Add the area
2085         {
2086                 //TimeTaker timer("initBlockMake() initialEmerge");
2087                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2088         }
2089
2090         // Data is ready now.
2091 }
2092
2093 MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
2094                 core::map<v3s16, MapBlock*> &changed_blocks)
2095 {
2096         v3s16 blockpos = data->blockpos;
2097         /*dstream<<"finishBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2098                         <<blockpos.Z<<")"<<std::endl;*/
2099
2100         if(data->no_op)
2101         {
2102                 //dstream<<"finishBlockMake(): no-op"<<std::endl;
2103                 return NULL;
2104         }
2105
2106         bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
2107
2108         /*dstream<<"Resulting vmanip:"<<std::endl;
2109         data->vmanip.print(dstream);*/
2110         
2111         /*
2112                 Blit generated stuff to map
2113                 NOTE: blitBackAll adds nearly everything to changed_blocks
2114         */
2115         {
2116                 // 70ms @cs=8
2117                 //TimeTaker timer("finishBlockMake() blitBackAll");
2118                 data->vmanip->blitBackAll(&changed_blocks);
2119         }
2120
2121         if(enable_mapgen_debug_info)
2122                 dstream<<"finishBlockMake: changed_blocks.size()="
2123                                 <<changed_blocks.size()<<std::endl;
2124
2125         /*
2126                 Copy transforming liquid information
2127         */
2128         while(data->transforming_liquid.size() > 0)
2129         {
2130                 v3s16 p = data->transforming_liquid.pop_front();
2131                 m_transforming_liquid.push_back(p);
2132         }
2133         
2134         /*
2135                 Get central block
2136         */
2137         MapBlock *block = getBlockNoCreateNoEx(data->blockpos);
2138         assert(block);
2139
2140         /*
2141                 Set is_underground flag for lighting with sunlight.
2142
2143                 Refer to map generator heuristics.
2144
2145                 NOTE: This is done in initChunkMake
2146         */
2147         //block->setIsUnderground(mapgen::block_is_underground(data->seed, blockpos));
2148
2149
2150         /*
2151                 Add sunlight to central block.
2152                 This makes in-dark-spawning monsters to not flood the whole thing.
2153                 Do not spread the light, though.
2154         */
2155         /*core::map<v3s16, bool> light_sources;
2156         bool black_air_left = false;
2157         block->propagateSunlight(light_sources, true, &black_air_left);*/
2158
2159         /*
2160                 NOTE: Lighting and object adding shouldn't really be here, but
2161                 lighting is a bit tricky to move properly to makeBlock.
2162                 TODO: Do this the right way anyway, that is, move it to makeBlock.
2163                       - There needs to be some way for makeBlock to report back if
2164                             the lighting update is going further down because of the
2165                                 new block blocking light
2166         */
2167
2168         /*
2169                 Update lighting
2170                 NOTE: This takes ~60ms, TODO: Investigate why
2171         */
2172         {
2173                 TimeTaker t("finishBlockMake lighting update");
2174
2175                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2176 #if 1
2177                 // Center block
2178                 lighting_update_blocks.insert(block->getPos(), block);
2179
2180                 /*{
2181                         s16 x = 0;
2182                         s16 z = 0;
2183                         v3s16 p = block->getPos()+v3s16(x,1,z);
2184                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2185                 }*/
2186 #endif
2187 #if 0
2188                 // All modified blocks
2189                 // NOTE: Should this be done? If this is not done, then the lighting
2190                 // of the others will be updated in a different place, one by one, i
2191                 // think... or they might not? Well, at least they are left marked as
2192                 // "lighting expired"; it seems that is not handled at all anywhere,
2193                 // so enabling this will slow it down A LOT because otherwise it
2194                 // would not do this at all. This causes the black trees.
2195                 for(core::map<v3s16, MapBlock*>::Iterator
2196                                 i = changed_blocks.getIterator();
2197                                 i.atEnd() == false; i++)
2198                 {
2199                         lighting_update_blocks.insert(i.getNode()->getKey(),
2200                                         i.getNode()->getValue());
2201                 }
2202                 /*// Also force-add all the upmost blocks for proper sunlight
2203                 for(s16 x=-1; x<=1; x++)
2204                 for(s16 z=-1; z<=1; z++)
2205                 {
2206                         v3s16 p = block->getPos()+v3s16(x,1,z);
2207                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2208                 }*/
2209 #endif
2210                 updateLighting(lighting_update_blocks, changed_blocks);
2211                 
2212                 /*
2213                         Set lighting to non-expired state in all of them.
2214                         This is cheating, but it is not fast enough if all of them
2215                         would actually be updated.
2216                 */
2217                 for(s16 x=-1; x<=1; x++)
2218                 for(s16 y=-1; y<=1; y++)
2219                 for(s16 z=-1; z<=1; z++)
2220                 {
2221                         v3s16 p = block->getPos()+v3s16(x,y,z);
2222                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2223                 }
2224
2225                 if(enable_mapgen_debug_info == false)
2226                         t.stop(true); // Hide output
2227         }
2228
2229         /*
2230                 Add random objects to block
2231         */
2232         mapgen::add_random_objects(block);
2233
2234         /*
2235                 Go through changed blocks
2236         */
2237         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
2238                         i.atEnd() == false; i++)
2239         {
2240                 MapBlock *block = i.getNode()->getValue();
2241                 assert(block);
2242                 /*
2243                         Update day/night difference cache of the MapBlocks
2244                 */
2245                 block->updateDayNightDiff();
2246                 /*
2247                         Set block as modified
2248                 */
2249                 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2250         }
2251
2252         /*
2253                 Set central block as generated
2254         */
2255         block->setGenerated(true);
2256         
2257         /*
2258                 Save changed parts of map
2259                 NOTE: Will be saved later.
2260         */
2261         //save(true);
2262
2263         /*dstream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
2264                         <<blockpos.Z<<")"<<std::endl;*/
2265 #if 0
2266         if(enable_mapgen_debug_info)
2267         {
2268                 /*
2269                         Analyze resulting blocks
2270                 */
2271                 for(s16 x=-1; x<=1; x++)
2272                 for(s16 y=-1; y<=1; y++)
2273                 for(s16 z=-1; z<=1; z++)
2274                 {
2275                         v3s16 p = block->getPos()+v3s16(x,y,z);
2276                         MapBlock *block = getBlockNoCreateNoEx(p);
2277                         char spos[20];
2278                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2279                         dstream<<"Generated "<<spos<<": "
2280                                         <<analyze_block(block)<<std::endl;
2281                 }
2282         }
2283 #endif
2284
2285         return block;
2286 }
2287
2288 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2289 {
2290         DSTACKF("%s: p2d=(%d,%d)",
2291                         __FUNCTION_NAME,
2292                         p2d.X, p2d.Y);
2293         
2294         /*
2295                 Check if it exists already in memory
2296         */
2297         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2298         if(sector != NULL)
2299                 return sector;
2300         
2301         /*
2302                 Try to load it from disk (with blocks)
2303         */
2304         //if(loadSectorFull(p2d) == true)
2305
2306         /*
2307                 Try to load metadata from disk
2308         */
2309         if(loadSectorMeta(p2d) == true)
2310         {
2311                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2312                 if(sector == NULL)
2313                 {
2314                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2315                         throw InvalidPositionException("");
2316                 }
2317                 return sector;
2318         }
2319
2320         /*
2321                 Do not create over-limit
2322         */
2323         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2324         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2325         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2326         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2327                 throw InvalidPositionException("createSector(): pos. over limit");
2328
2329         /*
2330                 Generate blank sector
2331         */
2332         
2333         sector = new ServerMapSector(this, p2d);
2334         
2335         // Sector position on map in nodes
2336         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2337
2338         /*
2339                 Insert to container
2340         */
2341         m_sectors.insert(p2d, sector);
2342         
2343         return sector;
2344 }
2345
2346 /*
2347         This is a quick-hand function for calling makeBlock().
2348 */
2349 MapBlock * ServerMap::generateBlock(
2350                 v3s16 p,
2351                 core::map<v3s16, MapBlock*> &modified_blocks
2352 )
2353 {
2354         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2355         
2356         /*dstream<<"generateBlock(): "
2357                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2358                         <<std::endl;*/
2359         
2360         bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
2361
2362         TimeTaker timer("generateBlock");
2363         
2364         //MapBlock *block = original_dummy;
2365                         
2366         v2s16 p2d(p.X, p.Z);
2367         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2368         
2369         /*
2370                 Do not generate over-limit
2371         */
2372         if(blockpos_over_limit(p))
2373         {
2374                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2375                 throw InvalidPositionException("generateBlock(): pos. over limit");
2376         }
2377
2378         /*
2379                 Create block make data
2380         */
2381         mapgen::BlockMakeData data;
2382         initBlockMake(&data, p);
2383
2384         /*
2385                 Generate block
2386         */
2387         {
2388                 TimeTaker t("mapgen::make_block()");
2389                 mapgen::make_block(&data);
2390
2391                 if(enable_mapgen_debug_info == false)
2392                         t.stop(true); // Hide output
2393         }
2394
2395         /*
2396                 Blit data back on map, update lighting, add mobs and whatever this does
2397         */
2398         finishBlockMake(&data, modified_blocks);
2399
2400         /*
2401                 Get central block
2402         */
2403         MapBlock *block = getBlockNoCreateNoEx(p);
2404
2405 #if 0
2406         /*
2407                 Check result
2408         */
2409         if(block)
2410         {
2411                 bool erroneus_content = false;
2412                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2413                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2414                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2415                 {
2416                         v3s16 p(x0,y0,z0);
2417                         MapNode n = block->getNode(p);
2418                         if(n.getContent() == CONTENT_IGNORE)
2419                         {
2420                                 dstream<<"CONTENT_IGNORE at "
2421                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2422                                                 <<std::endl;
2423                                 erroneus_content = true;
2424                                 assert(0);
2425                         }
2426                 }
2427                 if(erroneus_content)
2428                 {
2429                         assert(0);
2430                 }
2431         }
2432 #endif
2433
2434 #if 0
2435         /*
2436                 Generate a completely empty block
2437         */
2438         if(block)
2439         {
2440                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2441                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2442                 {
2443                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2444                         {
2445                                 MapNode n;
2446                                 if(y0%2==0)
2447                                         n.setContent(CONTENT_AIR);
2448                                 else
2449                                         n.setContent(CONTENT_STONE);
2450                                 block->setNode(v3s16(x0,y0,z0), n);
2451                         }
2452                 }
2453         }
2454 #endif
2455
2456         if(enable_mapgen_debug_info == false)
2457                 timer.stop(true); // Hide output
2458
2459         return block;
2460 }
2461
2462 MapBlock * ServerMap::createBlock(v3s16 p)
2463 {
2464         DSTACKF("%s: p=(%d,%d,%d)",
2465                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2466         
2467         /*
2468                 Do not create over-limit
2469         */
2470         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2471         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2472         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2473         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2474         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2475         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2476                 throw InvalidPositionException("createBlock(): pos. over limit");
2477         
2478         v2s16 p2d(p.X, p.Z);
2479         s16 block_y = p.Y;
2480         /*
2481                 This will create or load a sector if not found in memory.
2482                 If block exists on disk, it will be loaded.
2483
2484                 NOTE: On old save formats, this will be slow, as it generates
2485                       lighting on blocks for them.
2486         */
2487         ServerMapSector *sector;
2488         try{
2489                 sector = (ServerMapSector*)createSector(p2d);
2490                 assert(sector->getId() == MAPSECTOR_SERVER);
2491         }
2492         catch(InvalidPositionException &e)
2493         {
2494                 dstream<<"createBlock: createSector() failed"<<std::endl;
2495                 throw e;
2496         }
2497         /*
2498                 NOTE: This should not be done, or at least the exception
2499                 should not be passed on as std::exception, because it
2500                 won't be catched at all.
2501         */
2502         /*catch(std::exception &e)
2503         {
2504                 dstream<<"createBlock: createSector() failed: "
2505                                 <<e.what()<<std::endl;
2506                 throw e;
2507         }*/
2508
2509         /*
2510                 Try to get a block from the sector
2511         */
2512
2513         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2514         if(block)
2515         {
2516                 if(block->isDummy())
2517                         block->unDummify();
2518                 return block;
2519         }
2520         // Create blank
2521         block = sector->createBlankBlock(block_y);
2522         return block;
2523 }
2524
2525 MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
2526 {
2527         DSTACKF("%s: p=(%d,%d,%d), allow_generate=%d",
2528                         __FUNCTION_NAME,
2529                         p.X, p.Y, p.Z, allow_generate);
2530         
2531         {
2532                 MapBlock *block = getBlockNoCreateNoEx(p);
2533                 if(block && block->isDummy() == false)
2534                         return block;
2535         }
2536
2537         {
2538                 MapBlock *block = loadBlock(p);
2539                 if(block)
2540                         return block;
2541         }
2542
2543         if(allow_generate)
2544         {
2545                 core::map<v3s16, MapBlock*> modified_blocks;
2546                 MapBlock *block = generateBlock(p, modified_blocks);
2547                 if(block)
2548                 {
2549                         MapEditEvent event;
2550                         event.type = MEET_OTHER;
2551                         event.p = p;
2552
2553                         // Copy modified_blocks to event
2554                         for(core::map<v3s16, MapBlock*>::Iterator
2555                                         i = modified_blocks.getIterator();
2556                                         i.atEnd()==false; i++)
2557                         {
2558                                 event.modified_blocks.insert(i.getNode()->getKey(), false);
2559                         }
2560
2561                         // Queue event
2562                         dispatchEvent(&event);
2563                                                                 
2564                         return block;
2565                 }
2566         }
2567
2568         return NULL;
2569 }
2570
2571 #if 0
2572         /*
2573                 Do not generate over-limit
2574         */
2575         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2576         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2577         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2578         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2579         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2580         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2581                 throw InvalidPositionException("emergeBlock(): pos. over limit");
2582         
2583         v2s16 p2d(p.X, p.Z);
2584         s16 block_y = p.Y;
2585         /*
2586                 This will create or load a sector if not found in memory.
2587                 If block exists on disk, it will be loaded.
2588         */
2589         ServerMapSector *sector;
2590         try{
2591                 sector = createSector(p2d);
2592                 //sector = emergeSector(p2d, changed_blocks);
2593         }
2594         catch(InvalidPositionException &e)
2595         {
2596                 dstream<<"emergeBlock: createSector() failed: "
2597                                 <<e.what()<<std::endl;
2598                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
2599                                 <<std::endl
2600                                 <<"You could try to delete it."<<std::endl;
2601                 throw e;
2602         }
2603         catch(VersionMismatchException &e)
2604         {
2605                 dstream<<"emergeBlock: createSector() failed: "
2606                                 <<e.what()<<std::endl;
2607                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
2608                                 <<std::endl
2609                                 <<"You could try to delete it."<<std::endl;
2610                 throw e;
2611         }
2612
2613         /*
2614                 Try to get a block from the sector
2615         */
2616
2617         bool does_not_exist = false;
2618         bool lighting_expired = false;
2619         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2620         
2621         // If not found, try loading from disk
2622         if(block == NULL)
2623         {
2624                 block = loadBlock(p);
2625         }
2626         
2627         // Handle result
2628         if(block == NULL)
2629         {
2630                 does_not_exist = true;
2631         }
2632         else if(block->isDummy() == true)
2633         {
2634                 does_not_exist = true;
2635         }
2636         else if(block->getLightingExpired())
2637         {
2638                 lighting_expired = true;
2639         }
2640         else
2641         {
2642                 // Valid block
2643                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
2644                 return block;
2645         }
2646         
2647         /*
2648                 If block was not found on disk and not going to generate a
2649                 new one, make sure there is a dummy block in place.
2650         */
2651         if(only_from_disk && (does_not_exist || lighting_expired))
2652         {
2653                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
2654
2655                 if(block == NULL)
2656                 {
2657                         // Create dummy block
2658                         block = new MapBlock(this, p, true);
2659
2660                         // Add block to sector
2661                         sector->insertBlock(block);
2662                 }
2663                 // Done.
2664                 return block;
2665         }
2666
2667         //dstream<<"Not found on disk, generating."<<std::endl;
2668         // 0ms
2669         //TimeTaker("emergeBlock() generate");
2670
2671         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
2672
2673         /*
2674                 If the block doesn't exist, generate the block.
2675         */
2676         if(does_not_exist)
2677         {
2678                 block = generateBlock(p, block, sector, changed_blocks,
2679                                 lighting_invalidated_blocks); 
2680         }
2681
2682         if(lighting_expired)
2683         {
2684                 lighting_invalidated_blocks.insert(p, block);
2685         }
2686
2687 #if 0
2688         /*
2689                 Initially update sunlight
2690         */
2691         {
2692                 core::map<v3s16, bool> light_sources;
2693                 bool black_air_left = false;
2694                 bool bottom_invalid =
2695                                 block->propagateSunlight(light_sources, true,
2696                                 &black_air_left);
2697
2698                 // If sunlight didn't reach everywhere and part of block is
2699                 // above ground, lighting has to be properly updated
2700                 //if(black_air_left && some_part_underground)
2701                 if(black_air_left)
2702                 {
2703                         lighting_invalidated_blocks[block->getPos()] = block;
2704                 }
2705
2706                 if(bottom_invalid)
2707                 {
2708                         lighting_invalidated_blocks[block->getPos()] = block;
2709                 }
2710         }
2711 #endif
2712         
2713         return block;
2714 }
2715 #endif
2716
2717 s16 ServerMap::findGroundLevel(v2s16 p2d)
2718 {
2719 #if 0
2720         /*
2721                 Uh, just do something random...
2722         */
2723         // Find existing map from top to down
2724         s16 max=63;
2725         s16 min=-64;
2726         v3s16 p(p2d.X, max, p2d.Y);
2727         for(; p.Y>min; p.Y--)
2728         {
2729                 MapNode n = getNodeNoEx(p);
2730                 if(n.getContent() != CONTENT_IGNORE)
2731                         break;
2732         }
2733         if(p.Y == min)
2734                 goto plan_b;
2735         // If this node is not air, go to plan b
2736         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2737                 goto plan_b;
2738         // Search existing walkable and return it
2739         for(; p.Y>min; p.Y--)
2740         {
2741                 MapNode n = getNodeNoEx(p);
2742                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2743                         return p.Y;
2744         }
2745
2746         // Move to plan b
2747 plan_b:
2748 #endif
2749
2750         /*
2751                 Determine from map generator noise functions
2752         */
2753         
2754         s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1);
2755         return level;
2756
2757         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2758         //return (s16)level;
2759 }
2760
2761 void ServerMap::createDirs(std::string path)
2762 {
2763         if(fs::CreateAllDirs(path) == false)
2764         {
2765                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2766                                 <<"\""<<path<<"\""<<std::endl;
2767                 throw BaseException("ServerMap failed to create directory");
2768         }
2769 }
2770
2771 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2772 {
2773         char cc[9];
2774         switch(layout)
2775         {
2776                 case 1:
2777                         snprintf(cc, 9, "%.4x%.4x",
2778                                 (unsigned int)pos.X&0xffff,
2779                                 (unsigned int)pos.Y&0xffff);
2780
2781                         return m_savedir + "/sectors/" + cc;
2782                 case 2:
2783                         snprintf(cc, 9, "%.3x/%.3x",
2784                                 (unsigned int)pos.X&0xfff,
2785                                 (unsigned int)pos.Y&0xfff);
2786
2787                         return m_savedir + "/sectors2/" + cc;
2788                 default:
2789                         assert(false);
2790         }
2791 }
2792
2793 v2s16 ServerMap::getSectorPos(std::string dirname)
2794 {
2795         unsigned int x, y;
2796         int r;
2797         size_t spos = dirname.rfind('/') + 1;
2798         assert(spos != std::string::npos);
2799         if(dirname.size() - spos == 8)
2800         {
2801                 // Old layout
2802                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
2803         }
2804         else if(dirname.size() - spos == 3)
2805         {
2806                 // New layout
2807                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
2808                 // Sign-extend the 12 bit values up to 16 bits...
2809                 if(x&0x800) x|=0xF000;
2810                 if(y&0x800) y|=0xF000;
2811         }
2812         else
2813         {
2814                 assert(false);
2815         }
2816         assert(r == 2);
2817         v2s16 pos((s16)x, (s16)y);
2818         return pos;
2819 }
2820
2821 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2822 {
2823         v2s16 p2d = getSectorPos(sectordir);
2824
2825         if(blockfile.size() != 4){
2826                 throw InvalidFilenameException("Invalid block filename");
2827         }
2828         unsigned int y;
2829         int r = sscanf(blockfile.c_str(), "%4x", &y);
2830         if(r != 1)
2831                 throw InvalidFilenameException("Invalid block filename");
2832         return v3s16(p2d.X, y, p2d.Y);
2833 }
2834
2835 std::string ServerMap::getBlockFilename(v3s16 p)
2836 {
2837         char cc[5];
2838         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2839         return cc;
2840 }
2841
2842 void ServerMap::save(bool only_changed)
2843 {
2844         DSTACK(__FUNCTION_NAME);
2845         if(m_map_saving_enabled == false)
2846         {
2847                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2848                 return;
2849         }
2850         
2851         if(only_changed == false)
2852                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2853                                 <<std::endl;
2854         
2855         if(only_changed == false || m_map_metadata_changed)
2856         {
2857                 saveMapMeta();
2858         }
2859
2860         u32 sector_meta_count = 0;
2861         u32 block_count = 0;
2862         u32 block_count_all = 0; // Number of blocks in memory
2863         
2864         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2865         for(; i.atEnd() == false; i++)
2866         {
2867                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2868                 assert(sector->getId() == MAPSECTOR_SERVER);
2869         
2870                 if(sector->differs_from_disk || only_changed == false)
2871                 {
2872                         saveSectorMeta(sector);
2873                         sector_meta_count++;
2874                 }
2875                 core::list<MapBlock*> blocks;
2876                 sector->getBlocks(blocks);
2877                 core::list<MapBlock*>::Iterator j;
2878                 for(j=blocks.begin(); j!=blocks.end(); j++)
2879                 {
2880                         MapBlock *block = *j;
2881                         
2882                         block_count_all++;
2883
2884                         if(block->getModified() >= MOD_STATE_WRITE_NEEDED 
2885                                         || only_changed == false)
2886                         {
2887                                 saveBlock(block);
2888                                 block_count++;
2889
2890                                 /*dstream<<"ServerMap: Written block ("
2891                                                 <<block->getPos().X<<","
2892                                                 <<block->getPos().Y<<","
2893                                                 <<block->getPos().Z<<")"
2894                                                 <<std::endl;*/
2895                         }
2896                 }
2897         }
2898
2899         /*
2900                 Only print if something happened or saved whole map
2901         */
2902         if(only_changed == false || sector_meta_count != 0
2903                         || block_count != 0)
2904         {
2905                 dstream<<DTIME<<"ServerMap: Written: "
2906                                 <<sector_meta_count<<" sector metadata files, "
2907                                 <<block_count<<" block files"
2908                                 <<", "<<block_count_all<<" blocks in memory."
2909                                 <<std::endl;
2910         }
2911 }
2912
2913 void ServerMap::saveMapMeta()
2914 {
2915         DSTACK(__FUNCTION_NAME);
2916         
2917         dstream<<"INFO: ServerMap::saveMapMeta(): "
2918                         <<"seed="<<m_seed
2919                         <<std::endl;
2920
2921         createDirs(m_savedir);
2922         
2923         std::string fullpath = m_savedir + "/map_meta.txt";
2924         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
2925         if(os.good() == false)
2926         {
2927                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
2928                                 <<"could not open"<<fullpath<<std::endl;
2929                 throw FileNotGoodException("Cannot open chunk metadata");
2930         }
2931         
2932         Settings params;
2933         params.setU64("seed", m_seed);
2934
2935         params.writeLines(os);
2936
2937         os<<"[end_of_params]\n";
2938         
2939         m_map_metadata_changed = false;
2940 }
2941
2942 void ServerMap::loadMapMeta()
2943 {
2944         DSTACK(__FUNCTION_NAME);
2945         
2946         dstream<<"INFO: ServerMap::loadMapMeta(): Loading map metadata"
2947                         <<std::endl;
2948
2949         std::string fullpath = m_savedir + "/map_meta.txt";
2950         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2951         if(is.good() == false)
2952         {
2953                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
2954                                 <<"could not open"<<fullpath<<std::endl;
2955                 throw FileNotGoodException("Cannot open map metadata");
2956         }
2957
2958         Settings params;
2959
2960         for(;;)
2961         {
2962                 if(is.eof())
2963                         throw SerializationError
2964                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
2965                 std::string line;
2966                 std::getline(is, line);
2967                 std::string trimmedline = trim(line);
2968                 if(trimmedline == "[end_of_params]")
2969                         break;
2970                 params.parseConfigLine(line);
2971         }
2972
2973         m_seed = params.getU64("seed");
2974
2975         dstream<<"INFO: ServerMap::loadMapMeta(): "
2976                         <<"seed="<<m_seed
2977                         <<std::endl;
2978 }
2979
2980 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2981 {
2982         DSTACK(__FUNCTION_NAME);
2983         // Format used for writing
2984         u8 version = SER_FMT_VER_HIGHEST;
2985         // Get destination
2986         v2s16 pos = sector->getPos();
2987         std::string dir = getSectorDir(pos);
2988         createDirs(dir);
2989         
2990         std::string fullpath = dir + "/meta";
2991         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2992         if(o.good() == false)
2993                 throw FileNotGoodException("Cannot open sector metafile");
2994
2995         sector->serialize(o, version);
2996         
2997         sector->differs_from_disk = false;
2998 }
2999
3000 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3001 {
3002         DSTACK(__FUNCTION_NAME);
3003         // Get destination
3004         v2s16 p2d = getSectorPos(sectordir);
3005
3006         ServerMapSector *sector = NULL;
3007
3008         std::string fullpath = sectordir + "/meta";
3009         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3010         if(is.good() == false)
3011         {
3012                 // If the directory exists anyway, it probably is in some old
3013                 // format. Just go ahead and create the sector.
3014                 if(fs::PathExists(sectordir))
3015                 {
3016                         /*dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
3017                                         <<fullpath<<" doesn't exist but directory does."
3018                                         <<" Continuing with a sector with no metadata."
3019                                         <<std::endl;*/
3020                         sector = new ServerMapSector(this, p2d);
3021                         m_sectors.insert(p2d, sector);
3022                 }
3023                 else
3024                 {
3025                         throw FileNotGoodException("Cannot open sector metafile");
3026                 }
3027         }
3028         else
3029         {
3030                 sector = ServerMapSector::deSerialize
3031                                 (is, this, p2d, m_sectors);
3032                 if(save_after_load)
3033                         saveSectorMeta(sector);
3034         }
3035         
3036         sector->differs_from_disk = false;
3037
3038         return sector;
3039 }
3040
3041 bool ServerMap::loadSectorMeta(v2s16 p2d)
3042 {
3043         DSTACK(__FUNCTION_NAME);
3044
3045         MapSector *sector = NULL;
3046
3047         // The directory layout we're going to load from.
3048         //  1 - original sectors/xxxxzzzz/
3049         //  2 - new sectors2/xxx/zzz/
3050         //  If we load from anything but the latest structure, we will
3051         //  immediately save to the new one, and remove the old.
3052         int loadlayout = 1;
3053         std::string sectordir1 = getSectorDir(p2d, 1);
3054         std::string sectordir;
3055         if(fs::PathExists(sectordir1))
3056         {
3057                 sectordir = sectordir1;
3058         }
3059         else
3060         {
3061                 loadlayout = 2;
3062                 sectordir = getSectorDir(p2d, 2);
3063         }
3064
3065         try{
3066                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3067         }
3068         catch(InvalidFilenameException &e)
3069         {
3070                 return false;
3071         }
3072         catch(FileNotGoodException &e)
3073         {
3074                 return false;
3075         }
3076         catch(std::exception &e)
3077         {
3078                 return false;
3079         }
3080         
3081         return true;
3082 }
3083
3084 #if 0
3085 bool ServerMap::loadSectorFull(v2s16 p2d)
3086 {
3087         DSTACK(__FUNCTION_NAME);
3088
3089         MapSector *sector = NULL;
3090
3091         // The directory layout we're going to load from.
3092         //  1 - original sectors/xxxxzzzz/
3093         //  2 - new sectors2/xxx/zzz/
3094         //  If we load from anything but the latest structure, we will
3095         //  immediately save to the new one, and remove the old.
3096         int loadlayout = 1;
3097         std::string sectordir1 = getSectorDir(p2d, 1);
3098         std::string sectordir;
3099         if(fs::PathExists(sectordir1))
3100         {
3101                 sectordir = sectordir1;
3102         }
3103         else
3104         {
3105                 loadlayout = 2;
3106                 sectordir = getSectorDir(p2d, 2);
3107         }
3108
3109         try{
3110                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3111         }
3112         catch(InvalidFilenameException &e)
3113         {
3114                 return false;
3115         }
3116         catch(FileNotGoodException &e)
3117         {
3118                 return false;
3119         }
3120         catch(std::exception &e)
3121         {
3122                 return false;
3123         }
3124         
3125         /*
3126                 Load blocks
3127         */
3128         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3129                         (sectordir);
3130         std::vector<fs::DirListNode>::iterator i2;
3131         for(i2=list2.begin(); i2!=list2.end(); i2++)
3132         {
3133                 // We want files
3134                 if(i2->dir)
3135                         continue;
3136                 try{
3137                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3138                 }
3139                 catch(InvalidFilenameException &e)
3140                 {
3141                         // This catches unknown crap in directory
3142                 }
3143         }
3144
3145         if(loadlayout != 2)
3146         {
3147                 dstream<<"Sector converted to new layout - deleting "<<
3148                         sectordir1<<std::endl;
3149                 fs::RecursiveDelete(sectordir1);
3150         }
3151
3152         return true;
3153 }
3154 #endif
3155
3156 void ServerMap::saveBlock(MapBlock *block)
3157 {
3158         DSTACK(__FUNCTION_NAME);
3159         /*
3160                 Dummy blocks are not written
3161         */
3162         if(block->isDummy())
3163         {
3164                 /*v3s16 p = block->getPos();
3165                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3166                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3167                 return;
3168         }
3169
3170         // Format used for writing
3171         u8 version = SER_FMT_VER_HIGHEST;
3172         // Get destination
3173         v3s16 p3d = block->getPos();
3174         
3175         v2s16 p2d(p3d.X, p3d.Z);
3176         std::string sectordir = getSectorDir(p2d);
3177
3178         createDirs(sectordir);
3179
3180         std::string fullpath = sectordir+"/"+getBlockFilename(p3d);
3181         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3182         if(o.good() == false)
3183                 throw FileNotGoodException("Cannot open block data");
3184
3185         /*
3186                 [0] u8 serialization version
3187                 [1] data
3188         */
3189         o.write((char*)&version, 1);
3190         
3191         // Write basic data
3192         block->serialize(o, version);
3193         
3194         // Write extra data stored on disk
3195         block->serializeDiskExtra(o, version);
3196
3197         // We just wrote it to the disk so clear modified flag
3198         block->resetModified();
3199 }
3200
3201 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3202 {
3203         DSTACK(__FUNCTION_NAME);
3204
3205         std::string fullpath = sectordir+"/"+blockfile;
3206         try{
3207
3208                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3209                 if(is.good() == false)
3210                         throw FileNotGoodException("Cannot open block file");
3211                 
3212                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3213                 v2s16 p2d(p3d.X, p3d.Z);
3214                 
3215                 assert(sector->getPos() == p2d);
3216                 
3217                 u8 version = SER_FMT_VER_INVALID;
3218                 is.read((char*)&version, 1);
3219
3220                 if(is.fail())
3221                         throw SerializationError("ServerMap::loadBlock(): Failed"
3222                                         " to read MapBlock version");
3223
3224                 /*u32 block_size = MapBlock::serializedLength(version);
3225                 SharedBuffer<u8> data(block_size);
3226                 is.read((char*)*data, block_size);*/
3227
3228                 // This will always return a sector because we're the server
3229                 //MapSector *sector = emergeSector(p2d);
3230
3231                 MapBlock *block = NULL;
3232                 bool created_new = false;
3233                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3234                 if(block == NULL)
3235                 {
3236                         block = sector->createBlankBlockNoInsert(p3d.Y);
3237                         created_new = true;
3238                 }
3239                 
3240                 // Read basic data
3241                 block->deSerialize(is, version);
3242
3243                 // Read extra data stored on disk
3244                 block->deSerializeDiskExtra(is, version);
3245                 
3246                 // If it's a new block, insert it to the map
3247                 if(created_new)
3248                         sector->insertBlock(block);
3249                 
3250                 /*
3251                         Save blocks loaded in old format in new format
3252                 */
3253
3254                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3255                 {
3256                         saveBlock(block);
3257                 }
3258                 
3259                 // We just loaded it from the disk, so it's up-to-date.
3260                 block->resetModified();
3261
3262         }
3263         catch(SerializationError &e)
3264         {
3265                 dstream<<"WARNING: Invalid block data on disk "
3266                                 <<"fullpath="<<fullpath
3267                                 <<" (SerializationError). "
3268                                 <<"what()="<<e.what()
3269                                 <<std::endl;
3270                                 //" Ignoring. A new one will be generated.
3271                 assert(0);
3272
3273                 // TODO: Backup file; name is in fullpath.
3274         }
3275 }
3276
3277 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3278 {
3279         DSTACK(__FUNCTION_NAME);
3280
3281         v2s16 p2d(blockpos.X, blockpos.Z);
3282
3283         // The directory layout we're going to load from.
3284         //  1 - original sectors/xxxxzzzz/
3285         //  2 - new sectors2/xxx/zzz/
3286         //  If we load from anything but the latest structure, we will
3287         //  immediately save to the new one, and remove the old.
3288         int loadlayout = 1;
3289         std::string sectordir1 = getSectorDir(p2d, 1);
3290         std::string sectordir;
3291         if(fs::PathExists(sectordir1))
3292         {
3293                 sectordir = sectordir1;
3294         }
3295         else
3296         {
3297                 loadlayout = 2;
3298                 sectordir = getSectorDir(p2d, 2);
3299         }
3300         
3301         /*
3302                 Make sure sector is loaded
3303         */
3304         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3305         if(sector == NULL)
3306         {
3307                 try{
3308                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3309                 }
3310                 catch(InvalidFilenameException &e)
3311                 {
3312                         return false;
3313                 }
3314                 catch(FileNotGoodException &e)
3315                 {
3316                         return false;
3317                 }
3318                 catch(std::exception &e)
3319                 {
3320                         return false;
3321                 }
3322         }
3323         
3324         /*
3325                 Make sure file exists
3326         */
3327
3328         std::string blockfilename = getBlockFilename(blockpos);
3329         if(fs::PathExists(sectordir+"/"+blockfilename) == false)
3330                 return NULL;
3331
3332         /*
3333                 Load block
3334         */
3335         loadBlock(sectordir, blockfilename, sector, loadlayout != 2);
3336         return getBlockNoCreateNoEx(blockpos);
3337 }
3338
3339 void ServerMap::PrintInfo(std::ostream &out)
3340 {
3341         out<<"ServerMap: ";
3342 }
3343
3344 #ifndef SERVER
3345
3346 /*
3347         ClientMap
3348 */
3349
3350 ClientMap::ClientMap(
3351                 Client *client,
3352                 MapDrawControl &control,
3353                 scene::ISceneNode* parent,
3354                 scene::ISceneManager* mgr,
3355                 s32 id
3356 ):
3357         Map(dout_client),
3358         scene::ISceneNode(parent, mgr, id),
3359         m_client(client),
3360         m_control(control),
3361         m_camera_position(0,0,0),
3362         m_camera_direction(0,0,1)
3363 {
3364         m_camera_mutex.Init();
3365         assert(m_camera_mutex.IsInitialized());
3366         
3367         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3368                         BS*1000000,BS*1000000,BS*1000000);
3369 }
3370
3371 ClientMap::~ClientMap()
3372 {
3373         /*JMutexAutoLock lock(mesh_mutex);
3374         
3375         if(mesh != NULL)
3376         {
3377                 mesh->drop();
3378                 mesh = NULL;
3379         }*/
3380 }
3381
3382 MapSector * ClientMap::emergeSector(v2s16 p2d)
3383 {
3384         DSTACK(__FUNCTION_NAME);
3385         // Check that it doesn't exist already
3386         try{
3387                 return getSectorNoGenerate(p2d);
3388         }
3389         catch(InvalidPositionException &e)
3390         {
3391         }
3392         
3393         // Create a sector
3394         ClientMapSector *sector = new ClientMapSector(this, p2d);
3395         
3396         {
3397                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3398                 m_sectors.insert(p2d, sector);
3399         }
3400         
3401         return sector;
3402 }
3403
3404 #if 0
3405 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3406 {
3407         DSTACK(__FUNCTION_NAME);
3408         ClientMapSector *sector = NULL;
3409
3410         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3411         
3412         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3413
3414         if(n != NULL)
3415         {
3416                 sector = (ClientMapSector*)n->getValue();
3417                 assert(sector->getId() == MAPSECTOR_CLIENT);
3418         }
3419         else
3420         {
3421                 sector = new ClientMapSector(this, p2d);
3422                 {
3423                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3424                         m_sectors.insert(p2d, sector);
3425                 }
3426         }
3427
3428         sector->deSerialize(is);
3429 }
3430 #endif
3431
3432 void ClientMap::OnRegisterSceneNode()
3433 {
3434         if(IsVisible)
3435         {
3436                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3437                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3438         }
3439
3440         ISceneNode::OnRegisterSceneNode();
3441 }
3442
3443 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3444 {
3445         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3446         DSTACK(__FUNCTION_NAME);
3447
3448         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3449         
3450         /*
3451                 This is called two times per frame, reset on the non-transparent one
3452         */
3453         if(pass == scene::ESNRP_SOLID)
3454         {
3455                 m_last_drawn_sectors.clear();
3456         }
3457
3458         /*
3459                 Get time for measuring timeout.
3460                 
3461                 Measuring time is very useful for long delays when the
3462                 machine is swapping a lot.
3463         */
3464         int time1 = time(0);
3465
3466         //u32 daynight_ratio = m_client->getDayNightRatio();
3467
3468         m_camera_mutex.Lock();
3469         v3f camera_position = m_camera_position;
3470         v3f camera_direction = m_camera_direction;
3471         m_camera_mutex.Unlock();
3472
3473         /*
3474                 Get all blocks and draw all visible ones
3475         */
3476
3477         v3s16 cam_pos_nodes(
3478                         camera_position.X / BS,
3479                         camera_position.Y / BS,
3480                         camera_position.Z / BS);
3481
3482         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3483
3484         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3485         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3486
3487         // Take a fair amount as we will be dropping more out later
3488         v3s16 p_blocks_min(
3489                         p_nodes_min.X / MAP_BLOCKSIZE - 2,
3490                         p_nodes_min.Y / MAP_BLOCKSIZE - 2,
3491                         p_nodes_min.Z / MAP_BLOCKSIZE - 2);
3492         v3s16 p_blocks_max(
3493                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3494                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3495                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3496         
3497         u32 vertex_count = 0;
3498         
3499         // For limiting number of mesh updates per frame
3500         u32 mesh_update_count = 0;
3501         
3502         u32 blocks_would_have_drawn = 0;
3503         u32 blocks_drawn = 0;
3504
3505         int timecheck_counter = 0;
3506         core::map<v2s16, MapSector*>::Iterator si;
3507         si = m_sectors.getIterator();
3508         for(; si.atEnd() == false; si++)
3509         {
3510                 {
3511                         timecheck_counter++;
3512                         if(timecheck_counter > 50)
3513                         {
3514                                 timecheck_counter = 0;
3515                                 int time2 = time(0);
3516                                 if(time2 > time1 + 4)
3517                                 {
3518                                         dstream<<"ClientMap::renderMap(): "
3519                                                 "Rendering takes ages, returning."
3520                                                 <<std::endl;
3521                                         return;
3522                                 }
3523                         }
3524                 }
3525
3526                 MapSector *sector = si.getNode()->getValue();
3527                 v2s16 sp = sector->getPos();
3528                 
3529                 if(m_control.range_all == false)
3530                 {
3531                         if(sp.X < p_blocks_min.X
3532                         || sp.X > p_blocks_max.X
3533                         || sp.Y < p_blocks_min.Z
3534                         || sp.Y > p_blocks_max.Z)
3535                                 continue;
3536                 }
3537
3538                 core::list< MapBlock * > sectorblocks;
3539                 sector->getBlocks(sectorblocks);
3540                 
3541                 /*
3542                         Draw blocks
3543                 */
3544                 
3545                 u32 sector_blocks_drawn = 0;
3546
3547                 core::list< MapBlock * >::Iterator i;
3548                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3549                 {
3550                         MapBlock *block = *i;
3551
3552                         /*
3553                                 Compare block position to camera position, skip
3554                                 if not seen on display
3555                         */
3556                         
3557                         float range = 100000 * BS;
3558                         if(m_control.range_all == false)
3559                                 range = m_control.wanted_range * BS;
3560                         
3561                         float d = 0.0;
3562                         if(isBlockInSight(block->getPos(), camera_position,
3563                                         camera_direction, range, &d) == false)
3564                         {
3565                                 continue;
3566                         }
3567
3568                         // Okay, this block will be drawn. Reset usage timer.
3569                         block->resetUsageTimer();
3570                         
3571                         // This is ugly (spherical distance limit?)
3572                         /*if(m_control.range_all == false &&
3573                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
3574                                 continue;*/
3575
3576 #if 1
3577                         /*
3578                                 Update expired mesh (used for day/night change)
3579
3580                                 It doesn't work exactly like it should now with the
3581                                 tasked mesh update but whatever.
3582                         */
3583
3584                         bool mesh_expired = false;
3585                         
3586                         {
3587                                 JMutexAutoLock lock(block->mesh_mutex);
3588
3589                                 mesh_expired = block->getMeshExpired();
3590
3591                                 // Mesh has not been expired and there is no mesh:
3592                                 // block has no content
3593                                 if(block->mesh == NULL && mesh_expired == false)
3594                                         continue;
3595                         }
3596
3597                         f32 faraway = BS*50;
3598                         //f32 faraway = m_control.wanted_range * BS;
3599                         
3600                         /*
3601                                 This has to be done with the mesh_mutex unlocked
3602                         */
3603                         // Pretty random but this should work somewhat nicely
3604                         if(mesh_expired && (
3605                                         (mesh_update_count < 3
3606                                                 && (d < faraway || mesh_update_count < 2)
3607                                         )
3608                                         || 
3609                                         (m_control.range_all && mesh_update_count < 20)
3610                                 )
3611                         )
3612                         /*if(mesh_expired && mesh_update_count < 6
3613                                         && (d < faraway || mesh_update_count < 3))*/
3614                         {
3615                                 mesh_update_count++;
3616
3617                                 // Mesh has been expired: generate new mesh
3618                                 //block->updateMesh(daynight_ratio);
3619                                 m_client->addUpdateMeshTask(block->getPos());
3620
3621                                 mesh_expired = false;
3622                         }
3623                         
3624 #endif
3625                         /*
3626                                 Draw the faces of the block
3627                         */
3628                         {
3629                                 JMutexAutoLock lock(block->mesh_mutex);
3630
3631                                 scene::SMesh *mesh = block->mesh;
3632
3633                                 if(mesh == NULL)
3634                                         continue;
3635                                 
3636                                 blocks_would_have_drawn++;
3637                                 if(blocks_drawn >= m_control.wanted_max_blocks
3638                                                 && m_control.range_all == false
3639                                                 && d > m_control.wanted_min_range * BS)
3640                                         continue;
3641
3642                                 blocks_drawn++;
3643                                 sector_blocks_drawn++;
3644
3645                                 u32 c = mesh->getMeshBufferCount();
3646
3647                                 for(u32 i=0; i<c; i++)
3648                                 {
3649                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3650                                         const video::SMaterial& material = buf->getMaterial();
3651                                         video::IMaterialRenderer* rnd =
3652                                                         driver->getMaterialRenderer(material.MaterialType);
3653                                         bool transparent = (rnd && rnd->isTransparent());
3654                                         // Render transparent on transparent pass and likewise.
3655                                         if(transparent == is_transparent_pass)
3656                                         {
3657                                                 /*
3658                                                         This *shouldn't* hurt too much because Irrlicht
3659                                                         doesn't change opengl textures if the old
3660                                                         material is set again.
3661                                                 */
3662                                                 driver->setMaterial(buf->getMaterial());
3663                                                 driver->drawMeshBuffer(buf);
3664                                                 vertex_count += buf->getVertexCount();
3665                                         }
3666                                 }
3667                         }
3668                 } // foreach sectorblocks
3669
3670                 if(sector_blocks_drawn != 0)
3671                 {
3672                         m_last_drawn_sectors[sp] = true;
3673                 }
3674         }
3675         
3676         m_control.blocks_drawn = blocks_drawn;
3677         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
3678
3679         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3680                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3681 }
3682
3683 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
3684                 core::map<v3s16, MapBlock*> *affected_blocks)
3685 {
3686         bool changed = false;
3687         /*
3688                 Add it to all blocks touching it
3689         */
3690         v3s16 dirs[7] = {
3691                 v3s16(0,0,0), // this
3692                 v3s16(0,0,1), // back
3693                 v3s16(0,1,0), // top
3694                 v3s16(1,0,0), // right
3695                 v3s16(0,0,-1), // front
3696                 v3s16(0,-1,0), // bottom
3697                 v3s16(-1,0,0), // left
3698         };
3699         for(u16 i=0; i<7; i++)
3700         {
3701                 v3s16 p2 = p + dirs[i];
3702                 // Block position of neighbor (or requested) node
3703                 v3s16 blockpos = getNodeBlockPos(p2);
3704                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3705                 if(blockref == NULL)
3706                         continue;
3707                 // Relative position of requested node
3708                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3709                 if(blockref->setTempMod(relpos, mod))
3710                 {
3711                         changed = true;
3712                 }
3713         }
3714         if(changed && affected_blocks!=NULL)
3715         {
3716                 for(u16 i=0; i<7; i++)
3717                 {
3718                         v3s16 p2 = p + dirs[i];
3719                         // Block position of neighbor (or requested) node
3720                         v3s16 blockpos = getNodeBlockPos(p2);
3721                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3722                         if(blockref == NULL)
3723                                 continue;
3724                         affected_blocks->insert(blockpos, blockref);
3725                 }
3726         }
3727         return changed;
3728 }
3729
3730 bool ClientMap::clearTempMod(v3s16 p,
3731                 core::map<v3s16, MapBlock*> *affected_blocks)
3732 {
3733         bool changed = false;
3734         v3s16 dirs[7] = {
3735                 v3s16(0,0,0), // this
3736                 v3s16(0,0,1), // back
3737                 v3s16(0,1,0), // top
3738                 v3s16(1,0,0), // right
3739                 v3s16(0,0,-1), // front
3740                 v3s16(0,-1,0), // bottom
3741                 v3s16(-1,0,0), // left
3742         };
3743         for(u16 i=0; i<7; i++)
3744         {
3745                 v3s16 p2 = p + dirs[i];
3746                 // Block position of neighbor (or requested) node
3747                 v3s16 blockpos = getNodeBlockPos(p2);
3748                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3749                 if(blockref == NULL)
3750                         continue;
3751                 // Relative position of requested node
3752                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3753                 if(blockref->clearTempMod(relpos))
3754                 {
3755                         changed = true;
3756                 }
3757         }
3758         if(changed && affected_blocks!=NULL)
3759         {
3760                 for(u16 i=0; i<7; i++)
3761                 {
3762                         v3s16 p2 = p + dirs[i];
3763                         // Block position of neighbor (or requested) node
3764                         v3s16 blockpos = getNodeBlockPos(p2);
3765                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3766                         if(blockref == NULL)
3767                                 continue;
3768                         affected_blocks->insert(blockpos, blockref);
3769                 }
3770         }
3771         return changed;
3772 }
3773
3774 void ClientMap::expireMeshes(bool only_daynight_diffed)
3775 {
3776         TimeTaker timer("expireMeshes()");
3777
3778         core::map<v2s16, MapSector*>::Iterator si;
3779         si = m_sectors.getIterator();
3780         for(; si.atEnd() == false; si++)
3781         {
3782                 MapSector *sector = si.getNode()->getValue();
3783
3784                 core::list< MapBlock * > sectorblocks;
3785                 sector->getBlocks(sectorblocks);
3786                 
3787                 core::list< MapBlock * >::Iterator i;
3788                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3789                 {
3790                         MapBlock *block = *i;
3791
3792                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
3793                         {
3794                                 continue;
3795                         }
3796                         
3797                         {
3798                                 JMutexAutoLock lock(block->mesh_mutex);
3799                                 if(block->mesh != NULL)
3800                                 {
3801                                         /*block->mesh->drop();
3802                                         block->mesh = NULL;*/
3803                                         block->setMeshExpired(true);
3804                                 }
3805                         }
3806                 }
3807         }
3808 }
3809
3810 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
3811 {
3812         assert(mapType() == MAPTYPE_CLIENT);
3813
3814         try{
3815                 v3s16 p = blockpos + v3s16(0,0,0);
3816                 MapBlock *b = getBlockNoCreate(p);
3817                 b->updateMesh(daynight_ratio);
3818                 //b->setMeshExpired(true);
3819         }
3820         catch(InvalidPositionException &e){}
3821         // Leading edge
3822         try{
3823                 v3s16 p = blockpos + v3s16(-1,0,0);
3824                 MapBlock *b = getBlockNoCreate(p);
3825                 b->updateMesh(daynight_ratio);
3826                 //b->setMeshExpired(true);
3827         }
3828         catch(InvalidPositionException &e){}
3829         try{
3830                 v3s16 p = blockpos + v3s16(0,-1,0);
3831                 MapBlock *b = getBlockNoCreate(p);
3832                 b->updateMesh(daynight_ratio);
3833                 //b->setMeshExpired(true);
3834         }
3835         catch(InvalidPositionException &e){}
3836         try{
3837                 v3s16 p = blockpos + v3s16(0,0,-1);
3838                 MapBlock *b = getBlockNoCreate(p);
3839                 b->updateMesh(daynight_ratio);
3840                 //b->setMeshExpired(true);
3841         }
3842         catch(InvalidPositionException &e){}
3843 }
3844
3845 #if 0
3846 /*
3847         Update mesh of block in which the node is, and if the node is at the
3848         leading edge, update the appropriate leading blocks too.
3849 */
3850 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
3851 {
3852         v3s16 dirs[4] = {
3853                 v3s16(0,0,0),
3854                 v3s16(-1,0,0),
3855                 v3s16(0,-1,0),
3856                 v3s16(0,0,-1),
3857         };
3858         v3s16 blockposes[4];
3859         for(u32 i=0; i<4; i++)
3860         {
3861                 v3s16 np = nodepos + dirs[i];
3862                 blockposes[i] = getNodeBlockPos(np);
3863                 // Don't update mesh of block if it has been done already
3864                 bool already_updated = false;
3865                 for(u32 j=0; j<i; j++)
3866                 {
3867                         if(blockposes[j] == blockposes[i])
3868                         {
3869                                 already_updated = true;
3870                                 break;
3871                         }
3872                 }
3873                 if(already_updated)
3874                         continue;
3875                 // Update mesh
3876                 MapBlock *b = getBlockNoCreate(blockposes[i]);
3877                 b->updateMesh(daynight_ratio);
3878         }
3879 }
3880 #endif
3881
3882 void ClientMap::PrintInfo(std::ostream &out)
3883 {
3884         out<<"ClientMap: ";
3885 }
3886
3887 #endif // !SERVER
3888
3889 /*
3890         MapVoxelManipulator
3891 */
3892
3893 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3894 {
3895         m_map = map;
3896 }
3897
3898 MapVoxelManipulator::~MapVoxelManipulator()
3899 {
3900         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3901                         <<std::endl;*/
3902 }
3903
3904 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3905 {
3906         TimeTaker timer1("emerge", &emerge_time);
3907
3908         // Units of these are MapBlocks
3909         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3910         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3911
3912         VoxelArea block_area_nodes
3913                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3914
3915         addArea(block_area_nodes);
3916
3917         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3918         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3919         for(s32 x=p_min.X; x<=p_max.X; x++)
3920         {
3921                 v3s16 p(x,y,z);
3922                 core::map<v3s16, bool>::Node *n;
3923                 n = m_loaded_blocks.find(p);
3924                 if(n != NULL)
3925                         continue;
3926                 
3927                 bool block_data_inexistent = false;
3928                 try
3929                 {
3930                         TimeTaker timer1("emerge load", &emerge_load_time);
3931
3932                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3933                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3934                                         <<" wanted area: ";
3935                         a.print(dstream);
3936                         dstream<<std::endl;*/
3937                         
3938                         MapBlock *block = m_map->getBlockNoCreate(p);
3939                         if(block->isDummy())
3940                                 block_data_inexistent = true;
3941                         else
3942                                 block->copyTo(*this);
3943                 }
3944                 catch(InvalidPositionException &e)
3945                 {
3946                         block_data_inexistent = true;
3947                 }
3948
3949                 if(block_data_inexistent)
3950                 {
3951                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3952                         // Fill with VOXELFLAG_INEXISTENT
3953                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3954                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3955                         {
3956                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3957                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3958                         }
3959                 }
3960
3961                 m_loaded_blocks.insert(p, !block_data_inexistent);
3962         }
3963
3964         //dstream<<"emerge done"<<std::endl;
3965 }
3966
3967 /*
3968         SUGG: Add an option to only update eg. water and air nodes.
3969               This will make it interfere less with important stuff if
3970                   run on background.
3971 */
3972 void MapVoxelManipulator::blitBack
3973                 (core::map<v3s16, MapBlock*> & modified_blocks)
3974 {
3975         if(m_area.getExtent() == v3s16(0,0,0))
3976                 return;
3977         
3978         //TimeTaker timer1("blitBack");
3979
3980         /*dstream<<"blitBack(): m_loaded_blocks.size()="
3981                         <<m_loaded_blocks.size()<<std::endl;*/
3982         
3983         /*
3984                 Initialize block cache
3985         */
3986         v3s16 blockpos_last;
3987         MapBlock *block = NULL;
3988         bool block_checked_in_modified = false;
3989
3990         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3991         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3992         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3993         {
3994                 v3s16 p(x,y,z);
3995
3996                 u8 f = m_flags[m_area.index(p)];
3997                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3998                         continue;
3999
4000                 MapNode &n = m_data[m_area.index(p)];
4001                         
4002                 v3s16 blockpos = getNodeBlockPos(p);
4003                 
4004                 try
4005                 {
4006                         // Get block
4007                         if(block == NULL || blockpos != blockpos_last){
4008                                 block = m_map->getBlockNoCreate(blockpos);
4009                                 blockpos_last = blockpos;
4010                                 block_checked_in_modified = false;
4011                         }
4012                         
4013                         // Calculate relative position in block
4014                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4015
4016                         // Don't continue if nothing has changed here
4017                         if(block->getNode(relpos) == n)
4018                                 continue;
4019
4020                         //m_map->setNode(m_area.MinEdge + p, n);
4021                         block->setNode(relpos, n);
4022                         
4023                         /*
4024                                 Make sure block is in modified_blocks
4025                         */
4026                         if(block_checked_in_modified == false)
4027                         {
4028                                 modified_blocks[blockpos] = block;
4029                                 block_checked_in_modified = true;
4030                         }
4031                 }
4032                 catch(InvalidPositionException &e)
4033                 {
4034                 }
4035         }
4036 }
4037
4038 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4039                 MapVoxelManipulator(map),
4040                 m_create_area(false)
4041 {
4042 }
4043
4044 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4045 {
4046 }
4047
4048 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4049 {
4050         // Just create the area so that it can be pointed to
4051         VoxelManipulator::emerge(a, caller_id);
4052 }
4053
4054 void ManualMapVoxelManipulator::initialEmerge(
4055                 v3s16 blockpos_min, v3s16 blockpos_max)
4056 {
4057         TimeTaker timer1("initialEmerge", &emerge_time);
4058
4059         // Units of these are MapBlocks
4060         v3s16 p_min = blockpos_min;
4061         v3s16 p_max = blockpos_max;
4062
4063         VoxelArea block_area_nodes
4064                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4065         
4066         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4067         if(size_MB >= 1)
4068         {
4069                 dstream<<"initialEmerge: area: ";
4070                 block_area_nodes.print(dstream);
4071                 dstream<<" ("<<size_MB<<"MB)";
4072                 dstream<<std::endl;
4073         }
4074
4075         addArea(block_area_nodes);
4076
4077         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4078         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4079         for(s32 x=p_min.X; x<=p_max.X; x++)
4080         {
4081                 v3s16 p(x,y,z);
4082                 core::map<v3s16, bool>::Node *n;
4083                 n = m_loaded_blocks.find(p);
4084                 if(n != NULL)
4085                         continue;
4086                 
4087                 bool block_data_inexistent = false;
4088                 try
4089                 {
4090                         TimeTaker timer1("emerge load", &emerge_load_time);
4091
4092                         MapBlock *block = m_map->getBlockNoCreate(p);
4093                         if(block->isDummy())
4094                                 block_data_inexistent = true;
4095                         else
4096                                 block->copyTo(*this);
4097                 }
4098                 catch(InvalidPositionException &e)
4099                 {
4100                         block_data_inexistent = true;
4101                 }
4102
4103                 if(block_data_inexistent)
4104                 {
4105                         /*
4106                                 Mark area inexistent
4107                         */
4108                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4109                         // Fill with VOXELFLAG_INEXISTENT
4110                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4111                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4112                         {
4113                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4114                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4115                         }
4116                 }
4117
4118                 m_loaded_blocks.insert(p, !block_data_inexistent);
4119         }
4120 }
4121
4122 void ManualMapVoxelManipulator::blitBackAll(
4123                 core::map<v3s16, MapBlock*> * modified_blocks)
4124 {
4125         if(m_area.getExtent() == v3s16(0,0,0))
4126                 return;
4127         
4128         /*
4129                 Copy data of all blocks
4130         */
4131         for(core::map<v3s16, bool>::Iterator
4132                         i = m_loaded_blocks.getIterator();
4133                         i.atEnd() == false; i++)
4134         {
4135                 v3s16 p = i.getNode()->getKey();
4136                 bool existed = i.getNode()->getValue();
4137                 if(existed == false)
4138                 {
4139                         // The Great Bug was found using this
4140                         /*dstream<<"ManualMapVoxelManipulator::blitBackAll: "
4141                                         <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4142                                         <<std::endl;*/
4143                         continue;
4144                 }
4145                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4146                 if(block == NULL)
4147                 {
4148                         dstream<<"WARNING: "<<__FUNCTION_NAME
4149                                         <<": got NULL block "
4150                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4151                                         <<std::endl;
4152                         continue;
4153                 }
4154
4155                 block->copyFrom(*this);
4156
4157                 if(modified_blocks)
4158                         modified_blocks->insert(p, block);
4159         }
4160 }
4161
4162 //END