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