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