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