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