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