]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
fa88e846f2bc03b4c4327aa98935389841839f14
[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         while(m_transforming_liquid.size() != 0)
1566         {
1567                 // This should be done here so that it is done when continue is used
1568                 if(loopcount >= initial_size * 3)
1569                         break;
1570                 loopcount++;
1571
1572                 /*
1573                         Get a queued transforming liquid node
1574                 */
1575                 v3s16 p0 = m_transforming_liquid.pop_front();
1576
1577                 MapNode n0 = getNodeNoEx(p0);
1578
1579                 /*
1580                         Collect information about current node
1581                  */
1582                 s8 liquid_level = -1;
1583                 u8 liquid_kind = CONTENT_IGNORE;
1584                 LiquidType liquid_type = content_features(n0.getContent()).liquid_type;
1585                 switch (liquid_type) {
1586                         case LIQUID_SOURCE:
1587                                 liquid_level = LIQUID_LEVEL_SOURCE;
1588                                 liquid_kind = content_features(n0.getContent()).liquid_alternative_flowing;
1589                                 break;
1590                         case LIQUID_FLOWING:
1591                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
1592                                 liquid_kind = n0.getContent();
1593                                 break;
1594                         case LIQUID_NONE:
1595                                 // if this is an air node, it *could* be transformed into a liquid. otherwise,
1596                                 // continue with the next node.
1597                                 if (n0.getContent() != CONTENT_AIR)
1598                                         continue;
1599                                 liquid_kind = CONTENT_AIR;
1600                                 break;
1601                 }
1602
1603                 /*
1604                         Collect information about the environment
1605                  */
1606                 const v3s16 *dirs = g_6dirs;
1607                 NodeNeighbor sources[6]; // surrounding sources
1608                 int num_sources = 0;
1609                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
1610                 int num_flows = 0;
1611                 NodeNeighbor airs[6]; // surrounding air
1612                 int num_airs = 0;
1613                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
1614                 int num_neutrals = 0;
1615                 bool flowing_down = false;
1616                 for (u16 i = 0; i < 6; i++) {
1617                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1618                         switch (i) {
1619                                 case 1:
1620                                         nt = NEIGHBOR_UPPER;
1621                                         break;
1622                                 case 4:
1623                                         nt = NEIGHBOR_LOWER;
1624                                         break;
1625                         }
1626                         v3s16 npos = p0 + dirs[i];
1627                         NodeNeighbor nb = {getNodeNoEx(npos), nt, npos};
1628                         switch (content_features(nb.n.getContent()).liquid_type) {
1629                                 case LIQUID_NONE:
1630                                         if (nb.n.getContent() == CONTENT_AIR) {
1631                                                 airs[num_airs++] = nb;
1632                                                 // if the current node is a water source the neighbor
1633                                                 // should be enqueded for transformation regardless of whether the
1634                                                 // current node changes or not.
1635                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
1636                                                         m_transforming_liquid.push_back(npos);
1637                                                 // if the current node happens to be a flowing node, it will start to flow down here.
1638                                                 if (nb.t == NEIGHBOR_LOWER) {
1639                                                         flowing_down = true;
1640                                                 }
1641                                         } else {
1642                                                 neutrals[num_neutrals++] = nb;
1643                                         }
1644                                         break;
1645                                 case LIQUID_SOURCE:
1646                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter 
1647                                         if (liquid_kind == CONTENT_AIR)
1648                                                 liquid_kind = content_features(nb.n.getContent()).liquid_alternative_flowing;
1649                                         if (content_features(nb.n.getContent()).liquid_alternative_flowing !=liquid_kind) {
1650                                                 neutrals[num_neutrals++] = nb;
1651                                         } else {
1652                                                 sources[num_sources++] = nb;
1653                                         }
1654                                         break;
1655                                 case LIQUID_FLOWING:
1656                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1657                                         if (liquid_kind == CONTENT_AIR)
1658                                                 liquid_kind = content_features(nb.n.getContent()).liquid_alternative_flowing;
1659                                         if (content_features(nb.n.getContent()).liquid_alternative_flowing != liquid_kind) {
1660                                                 neutrals[num_neutrals++] = nb;
1661                                         } else {
1662                                                 flows[num_flows++] = nb;
1663                                                 if (nb.t == NEIGHBOR_LOWER)
1664                                                         flowing_down = true;
1665                                         }
1666                                         break;
1667                         }
1668                 }
1669
1670                 /*
1671                         decide on the type (and possibly level) of the current node
1672                  */
1673                 content_t new_node_content;
1674                 s8 new_node_level = -1;
1675                 if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
1676                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1677                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1678                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1679                         new_node_content = content_features(liquid_kind).liquid_alternative_source;
1680                 } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
1681                         // liquid_kind is set properly, see above
1682                         new_node_content = liquid_kind;
1683                         new_node_level = LIQUID_LEVEL_MAX;
1684                 } else {
1685                         // no surrounding sources, so get the maximum level that can flow into this node
1686                         for (u16 i = 0; i < num_flows; i++) {
1687                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1688                                 switch (flows[i].t) {
1689                                         case NEIGHBOR_UPPER:
1690                                                 if (nb_liquid_level + WATER_DROP_BOOST > new_node_level) {
1691                                                         new_node_level = LIQUID_LEVEL_MAX;
1692                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1693                                                                 new_node_level = nb_liquid_level + WATER_DROP_BOOST;
1694                                                 }
1695                                                 break;
1696                                         case NEIGHBOR_LOWER:
1697                                                 break;
1698                                         case NEIGHBOR_SAME_LEVEL:
1699                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1700                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > new_node_level) {
1701                                                         new_node_level = nb_liquid_level - 1;
1702                                                 }
1703                                                 break;
1704                                 }
1705                         }
1706                         // don't flow as far in open terrain - if there isn't at least one adjacent solid block,
1707                         // substract another unit from the resulting water level.
1708                         if (!flowing_down && new_node_level >= 1) {
1709                                 bool at_wall = false;
1710                                 for (u16 i = 0; i < num_neutrals; i++) {
1711                                         if (neutrals[i].t == NEIGHBOR_SAME_LEVEL) {
1712                                                 at_wall = true;
1713                                                 break;
1714                                         }
1715                                 }
1716                                 if (!at_wall)
1717                                         new_node_level -= 1;
1718                         }
1719
1720                         if (new_node_level >= 0)
1721                                 new_node_content = liquid_kind;
1722                         else
1723                                 new_node_content = CONTENT_AIR;
1724                 }
1725
1726                 /*
1727                         check if anything has changed. if not, just continue with the next node.
1728                  */
1729                 if (new_node_content == n0.getContent() && (content_features(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1730                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1731                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1732                                                                                  == flowing_down)))
1733                         continue;
1734
1735
1736                 /*
1737                         update the current node
1738                  */
1739                 bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1740                 if (content_features(new_node_content).liquid_type == LIQUID_FLOWING) {
1741                         // set level to last 3 bits, flowing down bit to 4th bit
1742                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1743                 } else {
1744                         // set the liquid level and flow bit to 0
1745                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1746                 }
1747                 n0.setContent(new_node_content);
1748                 setNode(p0, n0);
1749                 v3s16 blockpos = getNodeBlockPos(p0);
1750                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1751                 if(block != NULL)
1752                         modified_blocks.insert(blockpos, block);
1753
1754                 /*
1755                         enqueue neighbors for update if neccessary
1756                  */
1757                 switch (content_features(n0.getContent()).liquid_type) {
1758                         case LIQUID_SOURCE:
1759                                 // make sure source flows into all neighboring nodes
1760                                 for (u16 i = 0; i < num_flows; i++)
1761                                         if (flows[i].t != NEIGHBOR_UPPER)
1762                                                 m_transforming_liquid.push_back(flows[i].p);
1763                                 for (u16 i = 0; i < num_airs; i++)
1764                                         if (airs[i].t != NEIGHBOR_UPPER)
1765                                                 m_transforming_liquid.push_back(airs[i].p);
1766                                 break;
1767                         case LIQUID_NONE:
1768                                 // this flow has turned to air; neighboring flows might need to do the same
1769                                 for (u16 i = 0; i < num_flows; i++)
1770                                         m_transforming_liquid.push_back(flows[i].p);
1771                                 break;
1772                         case LIQUID_FLOWING:
1773                                 for (u16 i = 0; i < num_flows; i++) {
1774                                         u8 flow_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1775                                         // liquid_level is still the ORIGINAL level of this node.
1776                                         if (flows[i].t != NEIGHBOR_UPPER && ((flow_level < liquid_level || flow_level < new_node_level) ||
1777                                                 flow_down_enabled))
1778                                                 m_transforming_liquid.push_back(flows[i].p);
1779                                 }
1780                                 for (u16 i = 0; i < num_airs; i++) {
1781                                         if (airs[i].t != NEIGHBOR_UPPER && (airs[i].t == NEIGHBOR_LOWER || new_node_level > 0))
1782                                                 m_transforming_liquid.push_back(airs[i].p);
1783                                 }
1784                                 break;
1785                 }
1786         }
1787         //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1788 }
1789
1790 NodeMetadata* Map::getNodeMetadata(v3s16 p)
1791 {
1792         v3s16 blockpos = getNodeBlockPos(p);
1793         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1794         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1795         if(block == NULL)
1796         {
1797                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1798                                 <<std::endl;
1799                 return NULL;
1800         }
1801         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1802         return meta;
1803 }
1804
1805 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1806 {
1807         v3s16 blockpos = getNodeBlockPos(p);
1808         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1809         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1810         if(block == NULL)
1811         {
1812                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1813                                 <<std::endl;
1814                 return;
1815         }
1816         block->m_node_metadata.set(p_rel, meta);
1817 }
1818
1819 void Map::removeNodeMetadata(v3s16 p)
1820 {
1821         v3s16 blockpos = getNodeBlockPos(p);
1822         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1823         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1824         if(block == NULL)
1825         {
1826                 dstream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1827                                 <<std::endl;
1828                 return;
1829         }
1830         block->m_node_metadata.remove(p_rel);
1831 }
1832
1833 void Map::nodeMetadataStep(float dtime,
1834                 core::map<v3s16, MapBlock*> &changed_blocks)
1835 {
1836         /*
1837                 NOTE:
1838                 Currently there is no way to ensure that all the necessary
1839                 blocks are loaded when this is run. (They might get unloaded)
1840                 NOTE: ^- Actually, that might not be so. In a quick test it
1841                 reloaded a block with a furnace when I walked back to it from
1842                 a distance.
1843         */
1844         core::map<v2s16, MapSector*>::Iterator si;
1845         si = m_sectors.getIterator();
1846         for(; si.atEnd() == false; si++)
1847         {
1848                 MapSector *sector = si.getNode()->getValue();
1849                 core::list< MapBlock * > sectorblocks;
1850                 sector->getBlocks(sectorblocks);
1851                 core::list< MapBlock * >::Iterator i;
1852                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1853                 {
1854                         MapBlock *block = *i;
1855                         bool changed = block->m_node_metadata.step(dtime);
1856                         if(changed)
1857                                 changed_blocks[block->getPos()] = block;
1858                 }
1859         }
1860 }
1861
1862 /*
1863         ServerMap
1864 */
1865
1866 ServerMap::ServerMap(std::string savedir):
1867         Map(dout_server),
1868         m_seed(0),
1869         m_map_metadata_changed(true)
1870 {
1871         dstream<<__FUNCTION_NAME<<std::endl;
1872
1873         //m_chunksize = 8; // Takes a few seconds
1874
1875         m_seed = (((u64)(myrand()%0xffff)<<0)
1876                         + ((u64)(myrand()%0xffff)<<16)
1877                         + ((u64)(myrand()%0xffff)<<32)
1878                         + ((u64)(myrand()%0xffff)<<48));
1879
1880         /*
1881                 Experimental and debug stuff
1882         */
1883
1884         {
1885         }
1886
1887         /*
1888                 Try to load map; if not found, create a new one.
1889         */
1890
1891         m_savedir = savedir;
1892         m_map_saving_enabled = false;
1893
1894         try
1895         {
1896                 // If directory exists, check contents and load if possible
1897                 if(fs::PathExists(m_savedir))
1898                 {
1899                         // If directory is empty, it is safe to save into it.
1900                         if(fs::GetDirListing(m_savedir).size() == 0)
1901                         {
1902                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1903                                                 <<std::endl;
1904                                 m_map_saving_enabled = true;
1905                         }
1906                         else
1907                         {
1908                                 try{
1909                                         // Load map metadata (seed, chunksize)
1910                                         loadMapMeta();
1911                                 }
1912                                 catch(FileNotGoodException &e){
1913                                         dstream<<DTIME<<"WARNING: Could not load map metadata"
1914                                                         //<<" Disabling chunk-based generator."
1915                                                         <<std::endl;
1916                                         //m_chunksize = 0;
1917                                 }
1918
1919                                 /*try{
1920                                         // Load chunk metadata
1921                                         loadChunkMeta();
1922                                 }
1923                                 catch(FileNotGoodException &e){
1924                                         dstream<<DTIME<<"WARNING: Could not load chunk metadata."
1925                                                         <<" Disabling chunk-based generator."
1926                                                         <<std::endl;
1927                                         m_chunksize = 0;
1928                                 }*/
1929
1930                                 /*dstream<<DTIME<<"Server: Successfully loaded chunk "
1931                                                 "metadata and sector (0,0) from "<<savedir<<
1932                                                 ", assuming valid save directory."
1933                                                 <<std::endl;*/
1934
1935                                 dstream<<DTIME<<"INFO: Server: Successfully loaded map "
1936                                                 <<"and chunk metadata from "<<savedir
1937                                                 <<", assuming valid save directory."
1938                                                 <<std::endl;
1939
1940                                 m_map_saving_enabled = true;
1941                                 // Map loaded, not creating new one
1942                                 return;
1943                         }
1944                 }
1945                 // If directory doesn't exist, it is safe to save to it
1946                 else{
1947                         m_map_saving_enabled = true;
1948                 }
1949         }
1950         catch(std::exception &e)
1951         {
1952                 dstream<<DTIME<<"WARNING: Server: Failed to load map from "<<savedir
1953                                 <<", exception: "<<e.what()<<std::endl;
1954                 dstream<<"Please remove the map or fix it."<<std::endl;
1955                 dstream<<"WARNING: Map saving will be disabled."<<std::endl;
1956         }
1957
1958         dstream<<DTIME<<"INFO: Initializing new map."<<std::endl;
1959
1960         // Create zero sector
1961         emergeSector(v2s16(0,0));
1962
1963         // Initially write whole map
1964         save(false);
1965 }
1966
1967 ServerMap::~ServerMap()
1968 {
1969         dstream<<__FUNCTION_NAME<<std::endl;
1970
1971         try
1972         {
1973                 if(m_map_saving_enabled)
1974                 {
1975                         // Save only changed parts
1976                         save(true);
1977                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1978                 }
1979                 else
1980                 {
1981                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1982                 }
1983         }
1984         catch(std::exception &e)
1985         {
1986                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1987                                 <<", exception: "<<e.what()<<std::endl;
1988         }
1989
1990 #if 0
1991         /*
1992                 Free all MapChunks
1993         */
1994         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1995         for(; i.atEnd() == false; i++)
1996         {
1997                 MapChunk *chunk = i.getNode()->getValue();
1998                 delete chunk;
1999         }
2000 #endif
2001 }
2002
2003 void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
2004 {
2005         bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
2006         if(enable_mapgen_debug_info)
2007                 dstream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2008                                 <<blockpos.Z<<")"<<std::endl;
2009         
2010         // Do nothing if not inside limits (+-1 because of neighbors)
2011         if(blockpos_over_limit(blockpos - v3s16(1,1,1)) ||
2012                 blockpos_over_limit(blockpos + v3s16(1,1,1)))
2013         {
2014                 data->no_op = true;
2015                 return;
2016         }
2017         
2018         data->no_op = false;
2019         data->seed = m_seed;
2020         data->blockpos = blockpos;
2021
2022         /*
2023                 Create the whole area of this and the neighboring blocks
2024         */
2025         {
2026                 //TimeTaker timer("initBlockMake() create area");
2027                 
2028                 for(s16 x=-1; x<=1; x++)
2029                 for(s16 z=-1; z<=1; z++)
2030                 {
2031                         v2s16 sectorpos(blockpos.X+x, blockpos.Z+z);
2032                         // Sector metadata is loaded from disk if not already loaded.
2033                         ServerMapSector *sector = createSector(sectorpos);
2034                         assert(sector);
2035
2036                         for(s16 y=-1; y<=1; y++)
2037                         {
2038                                 v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z);
2039                                 //MapBlock *block = createBlock(p);
2040                                 // 1) get from memory, 2) load from disk
2041                                 MapBlock *block = emergeBlock(p, false);
2042                                 // 3) create a blank one
2043                                 if(block == NULL)
2044                                 {
2045                                         block = createBlock(p);
2046
2047                                         /*
2048                                                 Block gets sunlight if this is true.
2049
2050                                                 Refer to the map generator heuristics.
2051                                         */
2052                                         bool ug = mapgen::block_is_underground(data->seed, p);
2053                                         block->setIsUnderground(ug);
2054                                 }
2055
2056                                 // Lighting will not be valid after make_chunk is called
2057                                 block->setLightingExpired(true);
2058                                 // Lighting will be calculated
2059                                 //block->setLightingExpired(false);
2060                         }
2061                 }
2062         }
2063         
2064         /*
2065                 Now we have a big empty area.
2066
2067                 Make a ManualMapVoxelManipulator that contains this and the
2068                 neighboring blocks
2069         */
2070         
2071         // The area that contains this block and it's neighbors
2072         v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
2073         v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
2074         
2075         data->vmanip = new ManualMapVoxelManipulator(this);
2076         //data->vmanip->setMap(this);
2077
2078         // Add the area
2079         {
2080                 //TimeTaker timer("initBlockMake() initialEmerge");
2081                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2082         }
2083
2084         // Data is ready now.
2085 }
2086
2087 MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
2088                 core::map<v3s16, MapBlock*> &changed_blocks)
2089 {
2090         v3s16 blockpos = data->blockpos;
2091         /*dstream<<"finishBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2092                         <<blockpos.Z<<")"<<std::endl;*/
2093
2094         if(data->no_op)
2095         {
2096                 //dstream<<"finishBlockMake(): no-op"<<std::endl;
2097                 return NULL;
2098         }
2099
2100         bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
2101
2102         /*dstream<<"Resulting vmanip:"<<std::endl;
2103         data->vmanip.print(dstream);*/
2104         
2105         /*
2106                 Blit generated stuff to map
2107                 NOTE: blitBackAll adds nearly everything to changed_blocks
2108         */
2109         {
2110                 // 70ms @cs=8
2111                 //TimeTaker timer("finishBlockMake() blitBackAll");
2112                 data->vmanip->blitBackAll(&changed_blocks);
2113         }
2114
2115         if(enable_mapgen_debug_info)
2116                 dstream<<"finishBlockMake: changed_blocks.size()="
2117                                 <<changed_blocks.size()<<std::endl;
2118
2119         /*
2120                 Copy transforming liquid information
2121         */
2122         while(data->transforming_liquid.size() > 0)
2123         {
2124                 v3s16 p = data->transforming_liquid.pop_front();
2125                 m_transforming_liquid.push_back(p);
2126         }
2127         
2128         /*
2129                 Get central block
2130         */
2131         MapBlock *block = getBlockNoCreateNoEx(data->blockpos);
2132         assert(block);
2133
2134         /*
2135                 Set is_underground flag for lighting with sunlight.
2136
2137                 Refer to map generator heuristics.
2138
2139                 NOTE: This is done in initChunkMake
2140         */
2141         //block->setIsUnderground(mapgen::block_is_underground(data->seed, blockpos));
2142
2143
2144         /*
2145                 Add sunlight to central block.
2146                 This makes in-dark-spawning monsters to not flood the whole thing.
2147                 Do not spread the light, though.
2148         */
2149         /*core::map<v3s16, bool> light_sources;
2150         bool black_air_left = false;
2151         block->propagateSunlight(light_sources, true, &black_air_left);*/
2152
2153         /*
2154                 NOTE: Lighting and object adding shouldn't really be here, but
2155                 lighting is a bit tricky to move properly to makeBlock.
2156                 TODO: Do this the right way anyway, that is, move it to makeBlock.
2157                       - There needs to be some way for makeBlock to report back if
2158                             the lighting update is going further down because of the
2159                                 new block blocking light
2160         */
2161
2162         /*
2163                 Update lighting
2164                 NOTE: This takes ~60ms, TODO: Investigate why
2165         */
2166         {
2167                 TimeTaker t("finishBlockMake lighting update");
2168
2169                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2170 #if 1
2171                 // Center block
2172                 lighting_update_blocks.insert(block->getPos(), block);
2173
2174                 /*{
2175                         s16 x = 0;
2176                         s16 z = 0;
2177                         v3s16 p = block->getPos()+v3s16(x,1,z);
2178                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2179                 }*/
2180 #endif
2181 #if 0
2182                 // All modified blocks
2183                 // NOTE: Should this be done? If this is not done, then the lighting
2184                 // of the others will be updated in a different place, one by one, i
2185                 // think... or they might not? Well, at least they are left marked as
2186                 // "lighting expired"; it seems that is not handled at all anywhere,
2187                 // so enabling this will slow it down A LOT because otherwise it
2188                 // would not do this at all. This causes the black trees.
2189                 for(core::map<v3s16, MapBlock*>::Iterator
2190                                 i = changed_blocks.getIterator();
2191                                 i.atEnd() == false; i++)
2192                 {
2193                         lighting_update_blocks.insert(i.getNode()->getKey(),
2194                                         i.getNode()->getValue());
2195                 }
2196                 /*// Also force-add all the upmost blocks for proper sunlight
2197                 for(s16 x=-1; x<=1; x++)
2198                 for(s16 z=-1; z<=1; z++)
2199                 {
2200                         v3s16 p = block->getPos()+v3s16(x,1,z);
2201                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2202                 }*/
2203 #endif
2204                 updateLighting(lighting_update_blocks, changed_blocks);
2205                 
2206                 /*
2207                         Set lighting to non-expired state in all of them.
2208                         This is cheating, but it is not fast enough if all of them
2209                         would actually be updated.
2210                 */
2211                 for(s16 x=-1; x<=1; x++)
2212                 for(s16 y=-1; y<=1; y++)
2213                 for(s16 z=-1; z<=1; z++)
2214                 {
2215                         v3s16 p = block->getPos()+v3s16(x,y,z);
2216                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2217                 }
2218
2219                 if(enable_mapgen_debug_info == false)
2220                         t.stop(true); // Hide output
2221         }
2222
2223         /*
2224                 Add random objects to block
2225         */
2226         mapgen::add_random_objects(block);
2227
2228         /*
2229                 Go through changed blocks
2230         */
2231         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
2232                         i.atEnd() == false; i++)
2233         {
2234                 MapBlock *block = i.getNode()->getValue();
2235                 assert(block);
2236                 /*
2237                         Update day/night difference cache of the MapBlocks
2238                 */
2239                 block->updateDayNightDiff();
2240                 /*
2241                         Set block as modified
2242                 */
2243                 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2244         }
2245
2246         /*
2247                 Set central block as generated
2248         */
2249         block->setGenerated(true);
2250         
2251         /*
2252                 Save changed parts of map
2253                 NOTE: Will be saved later.
2254         */
2255         //save(true);
2256
2257         /*dstream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
2258                         <<blockpos.Z<<")"<<std::endl;*/
2259 #if 0
2260         if(enable_mapgen_debug_info)
2261         {
2262                 /*
2263                         Analyze resulting blocks
2264                 */
2265                 for(s16 x=-1; x<=1; x++)
2266                 for(s16 y=-1; y<=1; y++)
2267                 for(s16 z=-1; z<=1; z++)
2268                 {
2269                         v3s16 p = block->getPos()+v3s16(x,y,z);
2270                         MapBlock *block = getBlockNoCreateNoEx(p);
2271                         char spos[20];
2272                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2273                         dstream<<"Generated "<<spos<<": "
2274                                         <<analyze_block(block)<<std::endl;
2275                 }
2276         }
2277 #endif
2278
2279         return block;
2280 }
2281
2282 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2283 {
2284         DSTACKF("%s: p2d=(%d,%d)",
2285                         __FUNCTION_NAME,
2286                         p2d.X, p2d.Y);
2287         
2288         /*
2289                 Check if it exists already in memory
2290         */
2291         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2292         if(sector != NULL)
2293                 return sector;
2294         
2295         /*
2296                 Try to load it from disk (with blocks)
2297         */
2298         //if(loadSectorFull(p2d) == true)
2299
2300         /*
2301                 Try to load metadata from disk
2302         */
2303         if(loadSectorMeta(p2d) == true)
2304         {
2305                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2306                 if(sector == NULL)
2307                 {
2308                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2309                         throw InvalidPositionException("");
2310                 }
2311                 return sector;
2312         }
2313
2314         /*
2315                 Do not create over-limit
2316         */
2317         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2318         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2319         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2320         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2321                 throw InvalidPositionException("createSector(): pos. over limit");
2322
2323         /*
2324                 Generate blank sector
2325         */
2326         
2327         sector = new ServerMapSector(this, p2d);
2328         
2329         // Sector position on map in nodes
2330         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2331
2332         /*
2333                 Insert to container
2334         */
2335         m_sectors.insert(p2d, sector);
2336         
2337         return sector;
2338 }
2339
2340 /*
2341         This is a quick-hand function for calling makeBlock().
2342 */
2343 MapBlock * ServerMap::generateBlock(
2344                 v3s16 p,
2345                 core::map<v3s16, MapBlock*> &modified_blocks
2346 )
2347 {
2348         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2349         
2350         /*dstream<<"generateBlock(): "
2351                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2352                         <<std::endl;*/
2353         
2354         bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
2355
2356         TimeTaker timer("generateBlock");
2357         
2358         //MapBlock *block = original_dummy;
2359                         
2360         v2s16 p2d(p.X, p.Z);
2361         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2362         
2363         /*
2364                 Do not generate over-limit
2365         */
2366         if(blockpos_over_limit(p))
2367         {
2368                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2369                 throw InvalidPositionException("generateBlock(): pos. over limit");
2370         }
2371
2372         /*
2373                 Create block make data
2374         */
2375         mapgen::BlockMakeData data;
2376         initBlockMake(&data, p);
2377
2378         /*
2379                 Generate block
2380         */
2381         {
2382                 TimeTaker t("mapgen::make_block()");
2383                 mapgen::make_block(&data);
2384
2385                 if(enable_mapgen_debug_info == false)
2386                         t.stop(true); // Hide output
2387         }
2388
2389         /*
2390                 Blit data back on map, update lighting, add mobs and whatever this does
2391         */
2392         finishBlockMake(&data, modified_blocks);
2393
2394         /*
2395                 Get central block
2396         */
2397         MapBlock *block = getBlockNoCreateNoEx(p);
2398
2399 #if 0
2400         /*
2401                 Check result
2402         */
2403         if(block)
2404         {
2405                 bool erroneus_content = false;
2406                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2407                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2408                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2409                 {
2410                         v3s16 p(x0,y0,z0);
2411                         MapNode n = block->getNode(p);
2412                         if(n.getContent() == CONTENT_IGNORE)
2413                         {
2414                                 dstream<<"CONTENT_IGNORE at "
2415                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2416                                                 <<std::endl;
2417                                 erroneus_content = true;
2418                                 assert(0);
2419                         }
2420                 }
2421                 if(erroneus_content)
2422                 {
2423                         assert(0);
2424                 }
2425         }
2426 #endif
2427
2428 #if 0
2429         /*
2430                 Generate a completely empty block
2431         */
2432         if(block)
2433         {
2434                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2435                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2436                 {
2437                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2438                         {
2439                                 MapNode n;
2440                                 if(y0%2==0)
2441                                         n.setContent(CONTENT_AIR);
2442                                 else
2443                                         n.setContent(CONTENT_STONE);
2444                                 block->setNode(v3s16(x0,y0,z0), n);
2445                         }
2446                 }
2447         }
2448 #endif
2449
2450         if(enable_mapgen_debug_info == false)
2451                 timer.stop(true); // Hide output
2452
2453         return block;
2454 }
2455
2456 MapBlock * ServerMap::createBlock(v3s16 p)
2457 {
2458         DSTACKF("%s: p=(%d,%d,%d)",
2459                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2460         
2461         /*
2462                 Do not create over-limit
2463         */
2464         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2465         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2466         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2467         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2468         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2469         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2470                 throw InvalidPositionException("createBlock(): pos. over limit");
2471         
2472         v2s16 p2d(p.X, p.Z);
2473         s16 block_y = p.Y;
2474         /*
2475                 This will create or load a sector if not found in memory.
2476                 If block exists on disk, it will be loaded.
2477
2478                 NOTE: On old save formats, this will be slow, as it generates
2479                       lighting on blocks for them.
2480         */
2481         ServerMapSector *sector;
2482         try{
2483                 sector = (ServerMapSector*)createSector(p2d);
2484                 assert(sector->getId() == MAPSECTOR_SERVER);
2485         }
2486         catch(InvalidPositionException &e)
2487         {
2488                 dstream<<"createBlock: createSector() failed"<<std::endl;
2489                 throw e;
2490         }
2491         /*
2492                 NOTE: This should not be done, or at least the exception
2493                 should not be passed on as std::exception, because it
2494                 won't be catched at all.
2495         */
2496         /*catch(std::exception &e)
2497         {
2498                 dstream<<"createBlock: createSector() failed: "
2499                                 <<e.what()<<std::endl;
2500                 throw e;
2501         }*/
2502
2503         /*
2504                 Try to get a block from the sector
2505         */
2506
2507         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2508         if(block)
2509         {
2510                 if(block->isDummy())
2511                         block->unDummify();
2512                 return block;
2513         }
2514         // Create blank
2515         block = sector->createBlankBlock(block_y);
2516         return block;
2517 }
2518
2519 MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
2520 {
2521         DSTACKF("%s: p=(%d,%d,%d), allow_generate=%d",
2522                         __FUNCTION_NAME,
2523                         p.X, p.Y, p.Z, allow_generate);
2524         
2525         {
2526                 MapBlock *block = getBlockNoCreateNoEx(p);
2527                 if(block && block->isDummy() == false)
2528                         return block;
2529         }
2530
2531         {
2532                 MapBlock *block = loadBlock(p);
2533                 if(block)
2534                         return block;
2535         }
2536
2537         if(allow_generate)
2538         {
2539                 core::map<v3s16, MapBlock*> modified_blocks;
2540                 MapBlock *block = generateBlock(p, modified_blocks);
2541                 if(block)
2542                 {
2543                         MapEditEvent event;
2544                         event.type = MEET_OTHER;
2545                         event.p = p;
2546
2547                         // Copy modified_blocks to event
2548                         for(core::map<v3s16, MapBlock*>::Iterator
2549                                         i = modified_blocks.getIterator();
2550                                         i.atEnd()==false; i++)
2551                         {
2552                                 event.modified_blocks.insert(i.getNode()->getKey(), false);
2553                         }
2554
2555                         // Queue event
2556                         dispatchEvent(&event);
2557                                                                 
2558                         return block;
2559                 }
2560         }
2561
2562         return NULL;
2563 }
2564
2565 #if 0
2566         /*
2567                 Do not generate over-limit
2568         */
2569         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2570         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2571         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2572         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2573         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2574         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2575                 throw InvalidPositionException("emergeBlock(): pos. over limit");
2576         
2577         v2s16 p2d(p.X, p.Z);
2578         s16 block_y = p.Y;
2579         /*
2580                 This will create or load a sector if not found in memory.
2581                 If block exists on disk, it will be loaded.
2582         */
2583         ServerMapSector *sector;
2584         try{
2585                 sector = createSector(p2d);
2586                 //sector = emergeSector(p2d, changed_blocks);
2587         }
2588         catch(InvalidPositionException &e)
2589         {
2590                 dstream<<"emergeBlock: createSector() failed: "
2591                                 <<e.what()<<std::endl;
2592                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
2593                                 <<std::endl
2594                                 <<"You could try to delete it."<<std::endl;
2595                 throw e;
2596         }
2597         catch(VersionMismatchException &e)
2598         {
2599                 dstream<<"emergeBlock: createSector() failed: "
2600                                 <<e.what()<<std::endl;
2601                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
2602                                 <<std::endl
2603                                 <<"You could try to delete it."<<std::endl;
2604                 throw e;
2605         }
2606
2607         /*
2608                 Try to get a block from the sector
2609         */
2610
2611         bool does_not_exist = false;
2612         bool lighting_expired = false;
2613         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2614         
2615         // If not found, try loading from disk
2616         if(block == NULL)
2617         {
2618                 block = loadBlock(p);
2619         }
2620         
2621         // Handle result
2622         if(block == NULL)
2623         {
2624                 does_not_exist = true;
2625         }
2626         else if(block->isDummy() == true)
2627         {
2628                 does_not_exist = true;
2629         }
2630         else if(block->getLightingExpired())
2631         {
2632                 lighting_expired = true;
2633         }
2634         else
2635         {
2636                 // Valid block
2637                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
2638                 return block;
2639         }
2640         
2641         /*
2642                 If block was not found on disk and not going to generate a
2643                 new one, make sure there is a dummy block in place.
2644         */
2645         if(only_from_disk && (does_not_exist || lighting_expired))
2646         {
2647                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
2648
2649                 if(block == NULL)
2650                 {
2651                         // Create dummy block
2652                         block = new MapBlock(this, p, true);
2653
2654                         // Add block to sector
2655                         sector->insertBlock(block);
2656                 }
2657                 // Done.
2658                 return block;
2659         }
2660
2661         //dstream<<"Not found on disk, generating."<<std::endl;
2662         // 0ms
2663         //TimeTaker("emergeBlock() generate");
2664
2665         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
2666
2667         /*
2668                 If the block doesn't exist, generate the block.
2669         */
2670         if(does_not_exist)
2671         {
2672                 block = generateBlock(p, block, sector, changed_blocks,
2673                                 lighting_invalidated_blocks); 
2674         }
2675
2676         if(lighting_expired)
2677         {
2678                 lighting_invalidated_blocks.insert(p, block);
2679         }
2680
2681 #if 0
2682         /*
2683                 Initially update sunlight
2684         */
2685         {
2686                 core::map<v3s16, bool> light_sources;
2687                 bool black_air_left = false;
2688                 bool bottom_invalid =
2689                                 block->propagateSunlight(light_sources, true,
2690                                 &black_air_left);
2691
2692                 // If sunlight didn't reach everywhere and part of block is
2693                 // above ground, lighting has to be properly updated
2694                 //if(black_air_left && some_part_underground)
2695                 if(black_air_left)
2696                 {
2697                         lighting_invalidated_blocks[block->getPos()] = block;
2698                 }
2699
2700                 if(bottom_invalid)
2701                 {
2702                         lighting_invalidated_blocks[block->getPos()] = block;
2703                 }
2704         }
2705 #endif
2706         
2707         return block;
2708 }
2709 #endif
2710
2711 s16 ServerMap::findGroundLevel(v2s16 p2d)
2712 {
2713 #if 0
2714         /*
2715                 Uh, just do something random...
2716         */
2717         // Find existing map from top to down
2718         s16 max=63;
2719         s16 min=-64;
2720         v3s16 p(p2d.X, max, p2d.Y);
2721         for(; p.Y>min; p.Y--)
2722         {
2723                 MapNode n = getNodeNoEx(p);
2724                 if(n.getContent() != CONTENT_IGNORE)
2725                         break;
2726         }
2727         if(p.Y == min)
2728                 goto plan_b;
2729         // If this node is not air, go to plan b
2730         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2731                 goto plan_b;
2732         // Search existing walkable and return it
2733         for(; p.Y>min; p.Y--)
2734         {
2735                 MapNode n = getNodeNoEx(p);
2736                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2737                         return p.Y;
2738         }
2739
2740         // Move to plan b
2741 plan_b:
2742 #endif
2743
2744         /*
2745                 Determine from map generator noise functions
2746         */
2747         
2748         s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1);
2749         return level;
2750
2751         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2752         //return (s16)level;
2753 }
2754
2755 void ServerMap::createDirs(std::string path)
2756 {
2757         if(fs::CreateAllDirs(path) == false)
2758         {
2759                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2760                                 <<"\""<<path<<"\""<<std::endl;
2761                 throw BaseException("ServerMap failed to create directory");
2762         }
2763 }
2764
2765 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2766 {
2767         char cc[9];
2768         switch(layout)
2769         {
2770                 case 1:
2771                         snprintf(cc, 9, "%.4x%.4x",
2772                                 (unsigned int)pos.X&0xffff,
2773                                 (unsigned int)pos.Y&0xffff);
2774
2775                         return m_savedir + "/sectors/" + cc;
2776                 case 2:
2777                         snprintf(cc, 9, "%.3x/%.3x",
2778                                 (unsigned int)pos.X&0xfff,
2779                                 (unsigned int)pos.Y&0xfff);
2780
2781                         return m_savedir + "/sectors2/" + cc;
2782                 default:
2783                         assert(false);
2784         }
2785 }
2786
2787 v2s16 ServerMap::getSectorPos(std::string dirname)
2788 {
2789         unsigned int x, y;
2790         int r;
2791         size_t spos = dirname.rfind('/') + 1;
2792         assert(spos != std::string::npos);
2793         if(dirname.size() - spos == 8)
2794         {
2795                 // Old layout
2796                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
2797         }
2798         else if(dirname.size() - spos == 3)
2799         {
2800                 // New layout
2801                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
2802                 // Sign-extend the 12 bit values up to 16 bits...
2803                 if(x&0x800) x|=0xF000;
2804                 if(y&0x800) y|=0xF000;
2805         }
2806         else
2807         {
2808                 assert(false);
2809         }
2810         assert(r == 2);
2811         v2s16 pos((s16)x, (s16)y);
2812         return pos;
2813 }
2814
2815 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2816 {
2817         v2s16 p2d = getSectorPos(sectordir);
2818
2819         if(blockfile.size() != 4){
2820                 throw InvalidFilenameException("Invalid block filename");
2821         }
2822         unsigned int y;
2823         int r = sscanf(blockfile.c_str(), "%4x", &y);
2824         if(r != 1)
2825                 throw InvalidFilenameException("Invalid block filename");
2826         return v3s16(p2d.X, y, p2d.Y);
2827 }
2828
2829 std::string ServerMap::getBlockFilename(v3s16 p)
2830 {
2831         char cc[5];
2832         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2833         return cc;
2834 }
2835
2836 void ServerMap::save(bool only_changed)
2837 {
2838         DSTACK(__FUNCTION_NAME);
2839         if(m_map_saving_enabled == false)
2840         {
2841                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2842                 return;
2843         }
2844         
2845         if(only_changed == false)
2846                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2847                                 <<std::endl;
2848         
2849         if(only_changed == false || m_map_metadata_changed)
2850         {
2851                 saveMapMeta();
2852         }
2853
2854         u32 sector_meta_count = 0;
2855         u32 block_count = 0;
2856         u32 block_count_all = 0; // Number of blocks in memory
2857         
2858         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2859         for(; i.atEnd() == false; i++)
2860         {
2861                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2862                 assert(sector->getId() == MAPSECTOR_SERVER);
2863         
2864                 if(sector->differs_from_disk || only_changed == false)
2865                 {
2866                         saveSectorMeta(sector);
2867                         sector_meta_count++;
2868                 }
2869                 core::list<MapBlock*> blocks;
2870                 sector->getBlocks(blocks);
2871                 core::list<MapBlock*>::Iterator j;
2872                 for(j=blocks.begin(); j!=blocks.end(); j++)
2873                 {
2874                         MapBlock *block = *j;
2875                         
2876                         block_count_all++;
2877
2878                         if(block->getModified() >= MOD_STATE_WRITE_NEEDED 
2879                                         || only_changed == false)
2880                         {
2881                                 saveBlock(block);
2882                                 block_count++;
2883
2884                                 /*dstream<<"ServerMap: Written block ("
2885                                                 <<block->getPos().X<<","
2886                                                 <<block->getPos().Y<<","
2887                                                 <<block->getPos().Z<<")"
2888                                                 <<std::endl;*/
2889                         }
2890                 }
2891         }
2892
2893         /*
2894                 Only print if something happened or saved whole map
2895         */
2896         if(only_changed == false || sector_meta_count != 0
2897                         || block_count != 0)
2898         {
2899                 dstream<<DTIME<<"ServerMap: Written: "
2900                                 <<sector_meta_count<<" sector metadata files, "
2901                                 <<block_count<<" block files"
2902                                 <<", "<<block_count_all<<" blocks in memory."
2903                                 <<std::endl;
2904         }
2905 }
2906
2907 void ServerMap::saveMapMeta()
2908 {
2909         DSTACK(__FUNCTION_NAME);
2910         
2911         dstream<<"INFO: ServerMap::saveMapMeta(): "
2912                         <<"seed="<<m_seed
2913                         <<std::endl;
2914
2915         createDirs(m_savedir);
2916         
2917         std::string fullpath = m_savedir + "/map_meta.txt";
2918         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
2919         if(os.good() == false)
2920         {
2921                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
2922                                 <<"could not open"<<fullpath<<std::endl;
2923                 throw FileNotGoodException("Cannot open chunk metadata");
2924         }
2925         
2926         Settings params;
2927         params.setU64("seed", m_seed);
2928
2929         params.writeLines(os);
2930
2931         os<<"[end_of_params]\n";
2932         
2933         m_map_metadata_changed = false;
2934 }
2935
2936 void ServerMap::loadMapMeta()
2937 {
2938         DSTACK(__FUNCTION_NAME);
2939         
2940         dstream<<"INFO: ServerMap::loadMapMeta(): Loading map metadata"
2941                         <<std::endl;
2942
2943         std::string fullpath = m_savedir + "/map_meta.txt";
2944         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2945         if(is.good() == false)
2946         {
2947                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
2948                                 <<"could not open"<<fullpath<<std::endl;
2949                 throw FileNotGoodException("Cannot open map metadata");
2950         }
2951
2952         Settings params;
2953
2954         for(;;)
2955         {
2956                 if(is.eof())
2957                         throw SerializationError
2958                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
2959                 std::string line;
2960                 std::getline(is, line);
2961                 std::string trimmedline = trim(line);
2962                 if(trimmedline == "[end_of_params]")
2963                         break;
2964                 params.parseConfigLine(line);
2965         }
2966
2967         m_seed = params.getU64("seed");
2968
2969         dstream<<"INFO: ServerMap::loadMapMeta(): "
2970                         <<"seed="<<m_seed
2971                         <<std::endl;
2972 }
2973
2974 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2975 {
2976         DSTACK(__FUNCTION_NAME);
2977         // Format used for writing
2978         u8 version = SER_FMT_VER_HIGHEST;
2979         // Get destination
2980         v2s16 pos = sector->getPos();
2981         std::string dir = getSectorDir(pos);
2982         createDirs(dir);
2983         
2984         std::string fullpath = dir + "/meta";
2985         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2986         if(o.good() == false)
2987                 throw FileNotGoodException("Cannot open sector metafile");
2988
2989         sector->serialize(o, version);
2990         
2991         sector->differs_from_disk = false;
2992 }
2993
2994 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
2995 {
2996         DSTACK(__FUNCTION_NAME);
2997         // Get destination
2998         v2s16 p2d = getSectorPos(sectordir);
2999
3000         ServerMapSector *sector = NULL;
3001
3002         std::string fullpath = sectordir + "/meta";
3003         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3004         if(is.good() == false)
3005         {
3006                 // If the directory exists anyway, it probably is in some old
3007                 // format. Just go ahead and create the sector.
3008                 if(fs::PathExists(sectordir))
3009                 {
3010                         /*dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
3011                                         <<fullpath<<" doesn't exist but directory does."
3012                                         <<" Continuing with a sector with no metadata."
3013                                         <<std::endl;*/
3014                         sector = new ServerMapSector(this, p2d);
3015                         m_sectors.insert(p2d, sector);
3016                 }
3017                 else
3018                 {
3019                         throw FileNotGoodException("Cannot open sector metafile");
3020                 }
3021         }
3022         else
3023         {
3024                 sector = ServerMapSector::deSerialize
3025                                 (is, this, p2d, m_sectors);
3026                 if(save_after_load)
3027                         saveSectorMeta(sector);
3028         }
3029         
3030         sector->differs_from_disk = false;
3031
3032         return sector;
3033 }
3034
3035 bool ServerMap::loadSectorMeta(v2s16 p2d)
3036 {
3037         DSTACK(__FUNCTION_NAME);
3038
3039         MapSector *sector = NULL;
3040
3041         // The directory layout we're going to load from.
3042         //  1 - original sectors/xxxxzzzz/
3043         //  2 - new sectors2/xxx/zzz/
3044         //  If we load from anything but the latest structure, we will
3045         //  immediately save to the new one, and remove the old.
3046         int loadlayout = 1;
3047         std::string sectordir1 = getSectorDir(p2d, 1);
3048         std::string sectordir;
3049         if(fs::PathExists(sectordir1))
3050         {
3051                 sectordir = sectordir1;
3052         }
3053         else
3054         {
3055                 loadlayout = 2;
3056                 sectordir = getSectorDir(p2d, 2);
3057         }
3058
3059         try{
3060                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3061         }
3062         catch(InvalidFilenameException &e)
3063         {
3064                 return false;
3065         }
3066         catch(FileNotGoodException &e)
3067         {
3068                 return false;
3069         }
3070         catch(std::exception &e)
3071         {
3072                 return false;
3073         }
3074         
3075         return true;
3076 }
3077
3078 #if 0
3079 bool ServerMap::loadSectorFull(v2s16 p2d)
3080 {
3081         DSTACK(__FUNCTION_NAME);
3082
3083         MapSector *sector = NULL;
3084
3085         // The directory layout we're going to load from.
3086         //  1 - original sectors/xxxxzzzz/
3087         //  2 - new sectors2/xxx/zzz/
3088         //  If we load from anything but the latest structure, we will
3089         //  immediately save to the new one, and remove the old.
3090         int loadlayout = 1;
3091         std::string sectordir1 = getSectorDir(p2d, 1);
3092         std::string sectordir;
3093         if(fs::PathExists(sectordir1))
3094         {
3095                 sectordir = sectordir1;
3096         }
3097         else
3098         {
3099                 loadlayout = 2;
3100                 sectordir = getSectorDir(p2d, 2);
3101         }
3102
3103         try{
3104                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3105         }
3106         catch(InvalidFilenameException &e)
3107         {
3108                 return false;
3109         }
3110         catch(FileNotGoodException &e)
3111         {
3112                 return false;
3113         }
3114         catch(std::exception &e)
3115         {
3116                 return false;
3117         }
3118         
3119         /*
3120                 Load blocks
3121         */
3122         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3123                         (sectordir);
3124         std::vector<fs::DirListNode>::iterator i2;
3125         for(i2=list2.begin(); i2!=list2.end(); i2++)
3126         {
3127                 // We want files
3128                 if(i2->dir)
3129                         continue;
3130                 try{
3131                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3132                 }
3133                 catch(InvalidFilenameException &e)
3134                 {
3135                         // This catches unknown crap in directory
3136                 }
3137         }
3138
3139         if(loadlayout != 2)
3140         {
3141                 dstream<<"Sector converted to new layout - deleting "<<
3142                         sectordir1<<std::endl;
3143                 fs::RecursiveDelete(sectordir1);
3144         }
3145
3146         return true;
3147 }
3148 #endif
3149
3150 void ServerMap::saveBlock(MapBlock *block)
3151 {
3152         DSTACK(__FUNCTION_NAME);
3153         /*
3154                 Dummy blocks are not written
3155         */
3156         if(block->isDummy())
3157         {
3158                 /*v3s16 p = block->getPos();
3159                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3160                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3161                 return;
3162         }
3163
3164         // Format used for writing
3165         u8 version = SER_FMT_VER_HIGHEST;
3166         // Get destination
3167         v3s16 p3d = block->getPos();
3168         
3169         v2s16 p2d(p3d.X, p3d.Z);
3170         std::string sectordir = getSectorDir(p2d);
3171
3172         createDirs(sectordir);
3173
3174         std::string fullpath = sectordir+"/"+getBlockFilename(p3d);
3175         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3176         if(o.good() == false)
3177                 throw FileNotGoodException("Cannot open block data");
3178
3179         /*
3180                 [0] u8 serialization version
3181                 [1] data
3182         */
3183         o.write((char*)&version, 1);
3184         
3185         // Write basic data
3186         block->serialize(o, version);
3187         
3188         // Write extra data stored on disk
3189         block->serializeDiskExtra(o, version);
3190
3191         // We just wrote it to the disk so clear modified flag
3192         block->resetModified();
3193 }
3194
3195 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3196 {
3197         DSTACK(__FUNCTION_NAME);
3198
3199         std::string fullpath = sectordir+"/"+blockfile;
3200         try{
3201
3202                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3203                 if(is.good() == false)
3204                         throw FileNotGoodException("Cannot open block file");
3205                 
3206                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3207                 v2s16 p2d(p3d.X, p3d.Z);
3208                 
3209                 assert(sector->getPos() == p2d);
3210                 
3211                 u8 version = SER_FMT_VER_INVALID;
3212                 is.read((char*)&version, 1);
3213
3214                 if(is.fail())
3215                         throw SerializationError("ServerMap::loadBlock(): Failed"
3216                                         " to read MapBlock version");
3217
3218                 /*u32 block_size = MapBlock::serializedLength(version);
3219                 SharedBuffer<u8> data(block_size);
3220                 is.read((char*)*data, block_size);*/
3221
3222                 // This will always return a sector because we're the server
3223                 //MapSector *sector = emergeSector(p2d);
3224
3225                 MapBlock *block = NULL;
3226                 bool created_new = false;
3227                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3228                 if(block == NULL)
3229                 {
3230                         block = sector->createBlankBlockNoInsert(p3d.Y);
3231                         created_new = true;
3232                 }
3233                 
3234                 // Read basic data
3235                 block->deSerialize(is, version);
3236
3237                 // Read extra data stored on disk
3238                 block->deSerializeDiskExtra(is, version);
3239                 
3240                 // If it's a new block, insert it to the map
3241                 if(created_new)
3242                         sector->insertBlock(block);
3243                 
3244                 /*
3245                         Save blocks loaded in old format in new format
3246                 */
3247
3248                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3249                 {
3250                         saveBlock(block);
3251                 }
3252                 
3253                 // We just loaded it from the disk, so it's up-to-date.
3254                 block->resetModified();
3255
3256         }
3257         catch(SerializationError &e)
3258         {
3259                 dstream<<"WARNING: Invalid block data on disk "
3260                                 <<"fullpath="<<fullpath
3261                                 <<" (SerializationError). "
3262                                 <<"what()="<<e.what()
3263                                 <<std::endl;
3264                                 //" Ignoring. A new one will be generated.
3265                 assert(0);
3266
3267                 // TODO: Backup file; name is in fullpath.
3268         }
3269 }
3270
3271 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3272 {
3273         DSTACK(__FUNCTION_NAME);
3274
3275         v2s16 p2d(blockpos.X, blockpos.Z);
3276
3277         // The directory layout we're going to load from.
3278         //  1 - original sectors/xxxxzzzz/
3279         //  2 - new sectors2/xxx/zzz/
3280         //  If we load from anything but the latest structure, we will
3281         //  immediately save to the new one, and remove the old.
3282         int loadlayout = 1;
3283         std::string sectordir1 = getSectorDir(p2d, 1);
3284         std::string sectordir;
3285         if(fs::PathExists(sectordir1))
3286         {
3287                 sectordir = sectordir1;
3288         }
3289         else
3290         {
3291                 loadlayout = 2;
3292                 sectordir = getSectorDir(p2d, 2);
3293         }
3294         
3295         /*
3296                 Make sure sector is loaded
3297         */
3298         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3299         if(sector == NULL)
3300         {
3301                 try{
3302                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3303                 }
3304                 catch(InvalidFilenameException &e)
3305                 {
3306                         return false;
3307                 }
3308                 catch(FileNotGoodException &e)
3309                 {
3310                         return false;
3311                 }
3312                 catch(std::exception &e)
3313                 {
3314                         return false;
3315                 }
3316         }
3317         
3318         /*
3319                 Make sure file exists
3320         */
3321
3322         std::string blockfilename = getBlockFilename(blockpos);
3323         if(fs::PathExists(sectordir+"/"+blockfilename) == false)
3324                 return NULL;
3325
3326         /*
3327                 Load block
3328         */
3329         loadBlock(sectordir, blockfilename, sector, loadlayout != 2);
3330         return getBlockNoCreateNoEx(blockpos);
3331 }
3332
3333 void ServerMap::PrintInfo(std::ostream &out)
3334 {
3335         out<<"ServerMap: ";
3336 }
3337
3338 #ifndef SERVER
3339
3340 /*
3341         ClientMap
3342 */
3343
3344 ClientMap::ClientMap(
3345                 Client *client,
3346                 MapDrawControl &control,
3347                 scene::ISceneNode* parent,
3348                 scene::ISceneManager* mgr,
3349                 s32 id
3350 ):
3351         Map(dout_client),
3352         scene::ISceneNode(parent, mgr, id),
3353         m_client(client),
3354         m_control(control),
3355         m_camera_position(0,0,0),
3356         m_camera_direction(0,0,1)
3357 {
3358         m_camera_mutex.Init();
3359         assert(m_camera_mutex.IsInitialized());
3360         
3361         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3362                         BS*1000000,BS*1000000,BS*1000000);
3363 }
3364
3365 ClientMap::~ClientMap()
3366 {
3367         /*JMutexAutoLock lock(mesh_mutex);
3368         
3369         if(mesh != NULL)
3370         {
3371                 mesh->drop();
3372                 mesh = NULL;
3373         }*/
3374 }
3375
3376 MapSector * ClientMap::emergeSector(v2s16 p2d)
3377 {
3378         DSTACK(__FUNCTION_NAME);
3379         // Check that it doesn't exist already
3380         try{
3381                 return getSectorNoGenerate(p2d);
3382         }
3383         catch(InvalidPositionException &e)
3384         {
3385         }
3386         
3387         // Create a sector
3388         ClientMapSector *sector = new ClientMapSector(this, p2d);
3389         
3390         {
3391                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3392                 m_sectors.insert(p2d, sector);
3393         }
3394         
3395         return sector;
3396 }
3397
3398 #if 0
3399 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3400 {
3401         DSTACK(__FUNCTION_NAME);
3402         ClientMapSector *sector = NULL;
3403
3404         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3405         
3406         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3407
3408         if(n != NULL)
3409         {
3410                 sector = (ClientMapSector*)n->getValue();
3411                 assert(sector->getId() == MAPSECTOR_CLIENT);
3412         }
3413         else
3414         {
3415                 sector = new ClientMapSector(this, p2d);
3416                 {
3417                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3418                         m_sectors.insert(p2d, sector);
3419                 }
3420         }
3421
3422         sector->deSerialize(is);
3423 }
3424 #endif
3425
3426 void ClientMap::OnRegisterSceneNode()
3427 {
3428         if(IsVisible)
3429         {
3430                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3431                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3432         }
3433
3434         ISceneNode::OnRegisterSceneNode();
3435 }
3436
3437 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3438 {
3439         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3440         DSTACK(__FUNCTION_NAME);
3441
3442         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3443         
3444         /*
3445                 This is called two times per frame, reset on the non-transparent one
3446         */
3447         if(pass == scene::ESNRP_SOLID)
3448         {
3449                 m_last_drawn_sectors.clear();
3450         }
3451
3452         /*
3453                 Get time for measuring timeout.
3454                 
3455                 Measuring time is very useful for long delays when the
3456                 machine is swapping a lot.
3457         */
3458         int time1 = time(0);
3459
3460         //u32 daynight_ratio = m_client->getDayNightRatio();
3461
3462         m_camera_mutex.Lock();
3463         v3f camera_position = m_camera_position;
3464         v3f camera_direction = m_camera_direction;
3465         m_camera_mutex.Unlock();
3466
3467         /*
3468                 Get all blocks and draw all visible ones
3469         */
3470
3471         v3s16 cam_pos_nodes(
3472                         camera_position.X / BS,
3473                         camera_position.Y / BS,
3474                         camera_position.Z / BS);
3475
3476         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3477
3478         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3479         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3480
3481         // Take a fair amount as we will be dropping more out later
3482         v3s16 p_blocks_min(
3483                         p_nodes_min.X / MAP_BLOCKSIZE - 2,
3484                         p_nodes_min.Y / MAP_BLOCKSIZE - 2,
3485                         p_nodes_min.Z / MAP_BLOCKSIZE - 2);
3486         v3s16 p_blocks_max(
3487                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3488                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3489                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3490         
3491         u32 vertex_count = 0;
3492         
3493         // For limiting number of mesh updates per frame
3494         u32 mesh_update_count = 0;
3495         
3496         u32 blocks_would_have_drawn = 0;
3497         u32 blocks_drawn = 0;
3498
3499         int timecheck_counter = 0;
3500         core::map<v2s16, MapSector*>::Iterator si;
3501         si = m_sectors.getIterator();
3502         for(; si.atEnd() == false; si++)
3503         {
3504                 {
3505                         timecheck_counter++;
3506                         if(timecheck_counter > 50)
3507                         {
3508                                 timecheck_counter = 0;
3509                                 int time2 = time(0);
3510                                 if(time2 > time1 + 4)
3511                                 {
3512                                         dstream<<"ClientMap::renderMap(): "
3513                                                 "Rendering takes ages, returning."
3514                                                 <<std::endl;
3515                                         return;
3516                                 }
3517                         }
3518                 }
3519
3520                 MapSector *sector = si.getNode()->getValue();
3521                 v2s16 sp = sector->getPos();
3522                 
3523                 if(m_control.range_all == false)
3524                 {
3525                         if(sp.X < p_blocks_min.X
3526                         || sp.X > p_blocks_max.X
3527                         || sp.Y < p_blocks_min.Z
3528                         || sp.Y > p_blocks_max.Z)
3529                                 continue;
3530                 }
3531
3532                 core::list< MapBlock * > sectorblocks;
3533                 sector->getBlocks(sectorblocks);
3534                 
3535                 /*
3536                         Draw blocks
3537                 */
3538                 
3539                 u32 sector_blocks_drawn = 0;
3540
3541                 core::list< MapBlock * >::Iterator i;
3542                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3543                 {
3544                         MapBlock *block = *i;
3545
3546                         /*
3547                                 Compare block position to camera position, skip
3548                                 if not seen on display
3549                         */
3550                         
3551                         float range = 100000 * BS;
3552                         if(m_control.range_all == false)
3553                                 range = m_control.wanted_range * BS;
3554                         
3555                         float d = 0.0;
3556                         if(isBlockInSight(block->getPos(), camera_position,
3557                                         camera_direction, range, &d) == false)
3558                         {
3559                                 continue;
3560                         }
3561
3562                         // Okay, this block will be drawn. Reset usage timer.
3563                         block->resetUsageTimer();
3564                         
3565                         // This is ugly (spherical distance limit?)
3566                         /*if(m_control.range_all == false &&
3567                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
3568                                 continue;*/
3569
3570 #if 1
3571                         /*
3572                                 Update expired mesh (used for day/night change)
3573
3574                                 It doesn't work exactly like it should now with the
3575                                 tasked mesh update but whatever.
3576                         */
3577
3578                         bool mesh_expired = false;
3579                         
3580                         {
3581                                 JMutexAutoLock lock(block->mesh_mutex);
3582
3583                                 mesh_expired = block->getMeshExpired();
3584
3585                                 // Mesh has not been expired and there is no mesh:
3586                                 // block has no content
3587                                 if(block->mesh == NULL && mesh_expired == false)
3588                                         continue;
3589                         }
3590
3591                         f32 faraway = BS*50;
3592                         //f32 faraway = m_control.wanted_range * BS;
3593                         
3594                         /*
3595                                 This has to be done with the mesh_mutex unlocked
3596                         */
3597                         // Pretty random but this should work somewhat nicely
3598                         if(mesh_expired && (
3599                                         (mesh_update_count < 3
3600                                                 && (d < faraway || mesh_update_count < 2)
3601                                         )
3602                                         || 
3603                                         (m_control.range_all && mesh_update_count < 20)
3604                                 )
3605                         )
3606                         /*if(mesh_expired && mesh_update_count < 6
3607                                         && (d < faraway || mesh_update_count < 3))*/
3608                         {
3609                                 mesh_update_count++;
3610
3611                                 // Mesh has been expired: generate new mesh
3612                                 //block->updateMesh(daynight_ratio);
3613                                 m_client->addUpdateMeshTask(block->getPos());
3614
3615                                 mesh_expired = false;
3616                         }
3617                         
3618 #endif
3619                         /*
3620                                 Draw the faces of the block
3621                         */
3622                         {
3623                                 JMutexAutoLock lock(block->mesh_mutex);
3624
3625                                 scene::SMesh *mesh = block->mesh;
3626
3627                                 if(mesh == NULL)
3628                                         continue;
3629                                 
3630                                 blocks_would_have_drawn++;
3631                                 if(blocks_drawn >= m_control.wanted_max_blocks
3632                                                 && m_control.range_all == false
3633                                                 && d > m_control.wanted_min_range * BS)
3634                                         continue;
3635
3636                                 blocks_drawn++;
3637                                 sector_blocks_drawn++;
3638
3639                                 u32 c = mesh->getMeshBufferCount();
3640
3641                                 for(u32 i=0; i<c; i++)
3642                                 {
3643                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3644                                         const video::SMaterial& material = buf->getMaterial();
3645                                         video::IMaterialRenderer* rnd =
3646                                                         driver->getMaterialRenderer(material.MaterialType);
3647                                         bool transparent = (rnd && rnd->isTransparent());
3648                                         // Render transparent on transparent pass and likewise.
3649                                         if(transparent == is_transparent_pass)
3650                                         {
3651                                                 /*
3652                                                         This *shouldn't* hurt too much because Irrlicht
3653                                                         doesn't change opengl textures if the old
3654                                                         material is set again.
3655                                                 */
3656                                                 driver->setMaterial(buf->getMaterial());
3657                                                 driver->drawMeshBuffer(buf);
3658                                                 vertex_count += buf->getVertexCount();
3659                                         }
3660                                 }
3661                         }
3662                 } // foreach sectorblocks
3663
3664                 if(sector_blocks_drawn != 0)
3665                 {
3666                         m_last_drawn_sectors[sp] = true;
3667                 }
3668         }
3669         
3670         m_control.blocks_drawn = blocks_drawn;
3671         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
3672
3673         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3674                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3675 }
3676
3677 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
3678                 core::map<v3s16, MapBlock*> *affected_blocks)
3679 {
3680         bool changed = false;
3681         /*
3682                 Add it to all blocks touching it
3683         */
3684         v3s16 dirs[7] = {
3685                 v3s16(0,0,0), // this
3686                 v3s16(0,0,1), // back
3687                 v3s16(0,1,0), // top
3688                 v3s16(1,0,0), // right
3689                 v3s16(0,0,-1), // front
3690                 v3s16(0,-1,0), // bottom
3691                 v3s16(-1,0,0), // left
3692         };
3693         for(u16 i=0; i<7; i++)
3694         {
3695                 v3s16 p2 = p + dirs[i];
3696                 // Block position of neighbor (or requested) node
3697                 v3s16 blockpos = getNodeBlockPos(p2);
3698                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3699                 if(blockref == NULL)
3700                         continue;
3701                 // Relative position of requested node
3702                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3703                 if(blockref->setTempMod(relpos, mod))
3704                 {
3705                         changed = true;
3706                 }
3707         }
3708         if(changed && affected_blocks!=NULL)
3709         {
3710                 for(u16 i=0; i<7; i++)
3711                 {
3712                         v3s16 p2 = p + dirs[i];
3713                         // Block position of neighbor (or requested) node
3714                         v3s16 blockpos = getNodeBlockPos(p2);
3715                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3716                         if(blockref == NULL)
3717                                 continue;
3718                         affected_blocks->insert(blockpos, blockref);
3719                 }
3720         }
3721         return changed;
3722 }
3723
3724 bool ClientMap::clearTempMod(v3s16 p,
3725                 core::map<v3s16, MapBlock*> *affected_blocks)
3726 {
3727         bool changed = false;
3728         v3s16 dirs[7] = {
3729                 v3s16(0,0,0), // this
3730                 v3s16(0,0,1), // back
3731                 v3s16(0,1,0), // top
3732                 v3s16(1,0,0), // right
3733                 v3s16(0,0,-1), // front
3734                 v3s16(0,-1,0), // bottom
3735                 v3s16(-1,0,0), // left
3736         };
3737         for(u16 i=0; i<7; i++)
3738         {
3739                 v3s16 p2 = p + dirs[i];
3740                 // Block position of neighbor (or requested) node
3741                 v3s16 blockpos = getNodeBlockPos(p2);
3742                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3743                 if(blockref == NULL)
3744                         continue;
3745                 // Relative position of requested node
3746                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3747                 if(blockref->clearTempMod(relpos))
3748                 {
3749                         changed = true;
3750                 }
3751         }
3752         if(changed && affected_blocks!=NULL)
3753         {
3754                 for(u16 i=0; i<7; i++)
3755                 {
3756                         v3s16 p2 = p + dirs[i];
3757                         // Block position of neighbor (or requested) node
3758                         v3s16 blockpos = getNodeBlockPos(p2);
3759                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3760                         if(blockref == NULL)
3761                                 continue;
3762                         affected_blocks->insert(blockpos, blockref);
3763                 }
3764         }
3765         return changed;
3766 }
3767
3768 void ClientMap::expireMeshes(bool only_daynight_diffed)
3769 {
3770         TimeTaker timer("expireMeshes()");
3771
3772         core::map<v2s16, MapSector*>::Iterator si;
3773         si = m_sectors.getIterator();
3774         for(; si.atEnd() == false; si++)
3775         {
3776                 MapSector *sector = si.getNode()->getValue();
3777
3778                 core::list< MapBlock * > sectorblocks;
3779                 sector->getBlocks(sectorblocks);
3780                 
3781                 core::list< MapBlock * >::Iterator i;
3782                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3783                 {
3784                         MapBlock *block = *i;
3785
3786                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
3787                         {
3788                                 continue;
3789                         }
3790                         
3791                         {
3792                                 JMutexAutoLock lock(block->mesh_mutex);
3793                                 if(block->mesh != NULL)
3794                                 {
3795                                         /*block->mesh->drop();
3796                                         block->mesh = NULL;*/
3797                                         block->setMeshExpired(true);
3798                                 }
3799                         }
3800                 }
3801         }
3802 }
3803
3804 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
3805 {
3806         assert(mapType() == MAPTYPE_CLIENT);
3807
3808         try{
3809                 v3s16 p = blockpos + v3s16(0,0,0);
3810                 MapBlock *b = getBlockNoCreate(p);
3811                 b->updateMesh(daynight_ratio);
3812                 //b->setMeshExpired(true);
3813         }
3814         catch(InvalidPositionException &e){}
3815         // Leading edge
3816         try{
3817                 v3s16 p = blockpos + v3s16(-1,0,0);
3818                 MapBlock *b = getBlockNoCreate(p);
3819                 b->updateMesh(daynight_ratio);
3820                 //b->setMeshExpired(true);
3821         }
3822         catch(InvalidPositionException &e){}
3823         try{
3824                 v3s16 p = blockpos + v3s16(0,-1,0);
3825                 MapBlock *b = getBlockNoCreate(p);
3826                 b->updateMesh(daynight_ratio);
3827                 //b->setMeshExpired(true);
3828         }
3829         catch(InvalidPositionException &e){}
3830         try{
3831                 v3s16 p = blockpos + v3s16(0,0,-1);
3832                 MapBlock *b = getBlockNoCreate(p);
3833                 b->updateMesh(daynight_ratio);
3834                 //b->setMeshExpired(true);
3835         }
3836         catch(InvalidPositionException &e){}
3837 }
3838
3839 #if 0
3840 /*
3841         Update mesh of block in which the node is, and if the node is at the
3842         leading edge, update the appropriate leading blocks too.
3843 */
3844 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
3845 {
3846         v3s16 dirs[4] = {
3847                 v3s16(0,0,0),
3848                 v3s16(-1,0,0),
3849                 v3s16(0,-1,0),
3850                 v3s16(0,0,-1),
3851         };
3852         v3s16 blockposes[4];
3853         for(u32 i=0; i<4; i++)
3854         {
3855                 v3s16 np = nodepos + dirs[i];
3856                 blockposes[i] = getNodeBlockPos(np);
3857                 // Don't update mesh of block if it has been done already
3858                 bool already_updated = false;
3859                 for(u32 j=0; j<i; j++)
3860                 {
3861                         if(blockposes[j] == blockposes[i])
3862                         {
3863                                 already_updated = true;
3864                                 break;
3865                         }
3866                 }
3867                 if(already_updated)
3868                         continue;
3869                 // Update mesh
3870                 MapBlock *b = getBlockNoCreate(blockposes[i]);
3871                 b->updateMesh(daynight_ratio);
3872         }
3873 }
3874 #endif
3875
3876 void ClientMap::PrintInfo(std::ostream &out)
3877 {
3878         out<<"ClientMap: ";
3879 }
3880
3881 #endif // !SERVER
3882
3883 /*
3884         MapVoxelManipulator
3885 */
3886
3887 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3888 {
3889         m_map = map;
3890 }
3891
3892 MapVoxelManipulator::~MapVoxelManipulator()
3893 {
3894         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3895                         <<std::endl;*/
3896 }
3897
3898 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3899 {
3900         TimeTaker timer1("emerge", &emerge_time);
3901
3902         // Units of these are MapBlocks
3903         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3904         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3905
3906         VoxelArea block_area_nodes
3907                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3908
3909         addArea(block_area_nodes);
3910
3911         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3912         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3913         for(s32 x=p_min.X; x<=p_max.X; x++)
3914         {
3915                 v3s16 p(x,y,z);
3916                 core::map<v3s16, bool>::Node *n;
3917                 n = m_loaded_blocks.find(p);
3918                 if(n != NULL)
3919                         continue;
3920                 
3921                 bool block_data_inexistent = false;
3922                 try
3923                 {
3924                         TimeTaker timer1("emerge load", &emerge_load_time);
3925
3926                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3927                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3928                                         <<" wanted area: ";
3929                         a.print(dstream);
3930                         dstream<<std::endl;*/
3931                         
3932                         MapBlock *block = m_map->getBlockNoCreate(p);
3933                         if(block->isDummy())
3934                                 block_data_inexistent = true;
3935                         else
3936                                 block->copyTo(*this);
3937                 }
3938                 catch(InvalidPositionException &e)
3939                 {
3940                         block_data_inexistent = true;
3941                 }
3942
3943                 if(block_data_inexistent)
3944                 {
3945                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3946                         // Fill with VOXELFLAG_INEXISTENT
3947                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3948                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3949                         {
3950                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3951                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3952                         }
3953                 }
3954
3955                 m_loaded_blocks.insert(p, !block_data_inexistent);
3956         }
3957
3958         //dstream<<"emerge done"<<std::endl;
3959 }
3960
3961 /*
3962         SUGG: Add an option to only update eg. water and air nodes.
3963               This will make it interfere less with important stuff if
3964                   run on background.
3965 */
3966 void MapVoxelManipulator::blitBack
3967                 (core::map<v3s16, MapBlock*> & modified_blocks)
3968 {
3969         if(m_area.getExtent() == v3s16(0,0,0))
3970                 return;
3971         
3972         //TimeTaker timer1("blitBack");
3973
3974         /*dstream<<"blitBack(): m_loaded_blocks.size()="
3975                         <<m_loaded_blocks.size()<<std::endl;*/
3976         
3977         /*
3978                 Initialize block cache
3979         */
3980         v3s16 blockpos_last;
3981         MapBlock *block = NULL;
3982         bool block_checked_in_modified = false;
3983
3984         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3985         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3986         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3987         {
3988                 v3s16 p(x,y,z);
3989
3990                 u8 f = m_flags[m_area.index(p)];
3991                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3992                         continue;
3993
3994                 MapNode &n = m_data[m_area.index(p)];
3995                         
3996                 v3s16 blockpos = getNodeBlockPos(p);
3997                 
3998                 try
3999                 {
4000                         // Get block
4001                         if(block == NULL || blockpos != blockpos_last){
4002                                 block = m_map->getBlockNoCreate(blockpos);
4003                                 blockpos_last = blockpos;
4004                                 block_checked_in_modified = false;
4005                         }
4006                         
4007                         // Calculate relative position in block
4008                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4009
4010                         // Don't continue if nothing has changed here
4011                         if(block->getNode(relpos) == n)
4012                                 continue;
4013
4014                         //m_map->setNode(m_area.MinEdge + p, n);
4015                         block->setNode(relpos, n);
4016                         
4017                         /*
4018                                 Make sure block is in modified_blocks
4019                         */
4020                         if(block_checked_in_modified == false)
4021                         {
4022                                 modified_blocks[blockpos] = block;
4023                                 block_checked_in_modified = true;
4024                         }
4025                 }
4026                 catch(InvalidPositionException &e)
4027                 {
4028                 }
4029         }
4030 }
4031
4032 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4033                 MapVoxelManipulator(map),
4034                 m_create_area(false)
4035 {
4036 }
4037
4038 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4039 {
4040 }
4041
4042 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4043 {
4044         // Just create the area so that it can be pointed to
4045         VoxelManipulator::emerge(a, caller_id);
4046 }
4047
4048 void ManualMapVoxelManipulator::initialEmerge(
4049                 v3s16 blockpos_min, v3s16 blockpos_max)
4050 {
4051         TimeTaker timer1("initialEmerge", &emerge_time);
4052
4053         // Units of these are MapBlocks
4054         v3s16 p_min = blockpos_min;
4055         v3s16 p_max = blockpos_max;
4056
4057         VoxelArea block_area_nodes
4058                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4059         
4060         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4061         if(size_MB >= 1)
4062         {
4063                 dstream<<"initialEmerge: area: ";
4064                 block_area_nodes.print(dstream);
4065                 dstream<<" ("<<size_MB<<"MB)";
4066                 dstream<<std::endl;
4067         }
4068
4069         addArea(block_area_nodes);
4070
4071         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4072         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4073         for(s32 x=p_min.X; x<=p_max.X; x++)
4074         {
4075                 v3s16 p(x,y,z);
4076                 core::map<v3s16, bool>::Node *n;
4077                 n = m_loaded_blocks.find(p);
4078                 if(n != NULL)
4079                         continue;
4080                 
4081                 bool block_data_inexistent = false;
4082                 try
4083                 {
4084                         TimeTaker timer1("emerge load", &emerge_load_time);
4085
4086                         MapBlock *block = m_map->getBlockNoCreate(p);
4087                         if(block->isDummy())
4088                                 block_data_inexistent = true;
4089                         else
4090                                 block->copyTo(*this);
4091                 }
4092                 catch(InvalidPositionException &e)
4093                 {
4094                         block_data_inexistent = true;
4095                 }
4096
4097                 if(block_data_inexistent)
4098                 {
4099                         /*
4100                                 Mark area inexistent
4101                         */
4102                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4103                         // Fill with VOXELFLAG_INEXISTENT
4104                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4105                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4106                         {
4107                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4108                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4109                         }
4110                 }
4111
4112                 m_loaded_blocks.insert(p, !block_data_inexistent);
4113         }
4114 }
4115
4116 void ManualMapVoxelManipulator::blitBackAll(
4117                 core::map<v3s16, MapBlock*> * modified_blocks)
4118 {
4119         if(m_area.getExtent() == v3s16(0,0,0))
4120                 return;
4121         
4122         /*
4123                 Copy data of all blocks
4124         */
4125         for(core::map<v3s16, bool>::Iterator
4126                         i = m_loaded_blocks.getIterator();
4127                         i.atEnd() == false; i++)
4128         {
4129                 v3s16 p = i.getNode()->getKey();
4130                 bool existed = i.getNode()->getValue();
4131                 if(existed == false)
4132                 {
4133                         // The Great Bug was found using this
4134                         /*dstream<<"ManualMapVoxelManipulator::blitBackAll: "
4135                                         <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4136                                         <<std::endl;*/
4137                         continue;
4138                 }
4139                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4140                 if(block == NULL)
4141                 {
4142                         dstream<<"WARNING: "<<__FUNCTION_NAME
4143                                         <<": got NULL block "
4144                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4145                                         <<std::endl;
4146                         continue;
4147                 }
4148
4149                 block->copyFrom(*this);
4150
4151                 if(modified_blocks)
4152                         modified_blocks->insert(p, block);
4153         }
4154 }
4155
4156 //END