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