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