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