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