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