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