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