Move ClientMap to clientmap.{h,cpp}
[oweals/minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU 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         core::map<v3s16, MapBlock*>::Iterator i;
695         i = a_blocks.getIterator();
696         for(; i.atEnd() == false; i++)
697         {
698                 MapBlock *block = i.getNode()->getValue();
699
700                 for(;;)
701                 {
702                         // Don't bother with dummy blocks.
703                         if(block->isDummy())
704                                 break;
705
706                         v3s16 pos = block->getPos();
707                         modified_blocks.insert(pos, block);
708
709                         blocks_to_update.insert(pos, block);
710
711                         /*
712                                 Clear all light from block
713                         */
714                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
715                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
716                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
717                         {
718
719                                 try{
720                                         v3s16 p(x,y,z);
721                                         MapNode n = block->getNode(v3s16(x,y,z));
722                                         u8 oldlight = n.getLight(bank, nodemgr);
723                                         n.setLight(bank, 0, nodemgr);
724                                         block->setNode(v3s16(x,y,z), n);
725
726                                         // Collect borders for unlighting
727                                         if(x==0 || x == MAP_BLOCKSIZE-1
728                                         || y==0 || y == MAP_BLOCKSIZE-1
729                                         || z==0 || z == MAP_BLOCKSIZE-1)
730                                         {
731                                                 v3s16 p_map = p + v3s16(
732                                                                 MAP_BLOCKSIZE*pos.X,
733                                                                 MAP_BLOCKSIZE*pos.Y,
734                                                                 MAP_BLOCKSIZE*pos.Z);
735                                                 unlight_from.insert(p_map, oldlight);
736                                         }
737                                 }
738                                 catch(InvalidPositionException &e)
739                                 {
740                                         /*
741                                                 This would happen when dealing with a
742                                                 dummy block.
743                                         */
744                                         //assert(0);
745                                         infostream<<"updateLighting(): InvalidPositionException"
746                                                         <<std::endl;
747                                 }
748                         }
749
750                         if(bank == LIGHTBANK_DAY)
751                         {
752                                 bool bottom_valid = block->propagateSunlight(light_sources);
753
754                                 // If bottom is valid, we're done.
755                                 if(bottom_valid)
756                                         break;
757                         }
758                         else if(bank == LIGHTBANK_NIGHT)
759                         {
760                                 // For night lighting, sunlight is not propagated
761                                 break;
762                         }
763                         else
764                         {
765                                 // Invalid lighting bank
766                                 assert(0);
767                         }
768
769                         /*infostream<<"Bottom for sunlight-propagated block ("
770                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
771                                         <<std::endl;*/
772
773                         // Bottom sunlight is not valid; get the block and loop to it
774
775                         pos.Y--;
776                         try{
777                                 block = getBlockNoCreate(pos);
778                         }
779                         catch(InvalidPositionException &e)
780                         {
781                                 assert(0);
782                         }
783
784                 }
785         }
786         
787         /*
788                 Enable this to disable proper lighting for speeding up map
789                 generation for testing or whatever
790         */
791 #if 0
792         //if(g_settings->get(""))
793         {
794                 core::map<v3s16, MapBlock*>::Iterator i;
795                 i = blocks_to_update.getIterator();
796                 for(; i.atEnd() == false; i++)
797                 {
798                         MapBlock *block = i.getNode()->getValue();
799                         v3s16 p = block->getPos();
800                         block->setLightingExpired(false);
801                 }
802                 return;
803         }
804 #endif
805
806 #if 0
807         {
808                 TimeTaker timer("unspreadLight");
809                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
810         }
811
812         if(debug)
813         {
814                 u32 diff = modified_blocks.size() - count_was;
815                 count_was = modified_blocks.size();
816                 infostream<<"unspreadLight modified "<<diff<<std::endl;
817         }
818
819         {
820                 TimeTaker timer("spreadLight");
821                 spreadLight(bank, light_sources, modified_blocks);
822         }
823
824         if(debug)
825         {
826                 u32 diff = modified_blocks.size() - count_was;
827                 count_was = modified_blocks.size();
828                 infostream<<"spreadLight modified "<<diff<<std::endl;
829         }
830 #endif
831
832         {
833                 //MapVoxelManipulator vmanip(this);
834
835                 // Make a manual voxel manipulator and load all the blocks
836                 // that touch the requested blocks
837                 ManualMapVoxelManipulator vmanip(this);
838                 core::map<v3s16, MapBlock*>::Iterator i;
839                 i = blocks_to_update.getIterator();
840                 for(; i.atEnd() == false; i++)
841                 {
842                         MapBlock *block = i.getNode()->getValue();
843                         v3s16 p = block->getPos();
844
845                         // Add all surrounding blocks
846                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
847
848                         /*
849                                 Add all surrounding blocks that have up-to-date lighting
850                                 NOTE: This doesn't quite do the job (not everything
851                                           appropriate is lighted)
852                         */
853                         /*for(s16 z=-1; z<=1; z++)
854                         for(s16 y=-1; y<=1; y++)
855                         for(s16 x=-1; x<=1; x++)
856                         {
857                                 v3s16 p2 = p + v3s16(x,y,z);
858                                 MapBlock *block = getBlockNoCreateNoEx(p2);
859                                 if(block == NULL)
860                                         continue;
861                                 if(block->isDummy())
862                                         continue;
863                                 if(block->getLightingExpired())
864                                         continue;
865                                 vmanip.initialEmerge(p2, p2);
866                         }*/
867
868                         // Lighting of block will be updated completely
869                         block->setLightingExpired(false);
870                 }
871
872                 {
873                         //TimeTaker timer("unSpreadLight");
874                         vmanip.unspreadLight(bank, unlight_from, light_sources, nodemgr);
875                 }
876                 {
877                         //TimeTaker timer("spreadLight");
878                         vmanip.spreadLight(bank, light_sources, nodemgr);
879                 }
880                 {
881                         //TimeTaker timer("blitBack");
882                         vmanip.blitBack(modified_blocks);
883                 }
884                 /*infostream<<"emerge_time="<<emerge_time<<std::endl;
885                 emerge_time = 0;*/
886         }
887
888         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
889 }
890
891 void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
892                 core::map<v3s16, MapBlock*> & modified_blocks)
893 {
894         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
895         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
896
897         /*
898                 Update information about whether day and night light differ
899         */
900         for(core::map<v3s16, MapBlock*>::Iterator
901                         i = modified_blocks.getIterator();
902                         i.atEnd() == false; i++)
903         {
904                 MapBlock *block = i.getNode()->getValue();
905                 block->updateDayNightDiff();
906         }
907 }
908
909 /*
910 */
911 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
912                 core::map<v3s16, MapBlock*> &modified_blocks)
913 {
914         INodeDefManager *nodemgr = m_gamedef->ndef();
915
916         /*PrintInfo(m_dout);
917         m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
918                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
919
920         /*
921                 From this node to nodes underneath:
922                 If lighting is sunlight (1.0), unlight neighbours and
923                 set lighting to 0.
924                 Else discontinue.
925         */
926
927         v3s16 toppos = p + v3s16(0,1,0);
928         v3s16 bottompos = p + v3s16(0,-1,0);
929
930         bool node_under_sunlight = true;
931         core::map<v3s16, bool> light_sources;
932
933         /*
934                 If there is a node at top and it doesn't have sunlight,
935                 there has not been any sunlight going down.
936
937                 Otherwise there probably is.
938         */
939         try{
940                 MapNode topnode = getNode(toppos);
941
942                 if(topnode.getLight(LIGHTBANK_DAY, nodemgr) != LIGHT_SUN)
943                         node_under_sunlight = false;
944         }
945         catch(InvalidPositionException &e)
946         {
947         }
948
949         /*
950                 Remove all light that has come out of this node
951         */
952
953         enum LightBank banks[] =
954         {
955                 LIGHTBANK_DAY,
956                 LIGHTBANK_NIGHT
957         };
958         for(s32 i=0; i<2; i++)
959         {
960                 enum LightBank bank = banks[i];
961
962                 u8 lightwas = getNode(p).getLight(bank, nodemgr);
963
964                 // Add the block of the added node to modified_blocks
965                 v3s16 blockpos = getNodeBlockPos(p);
966                 MapBlock * block = getBlockNoCreate(blockpos);
967                 assert(block != NULL);
968                 modified_blocks.insert(blockpos, block);
969
970                 assert(isValidPosition(p));
971
972                 // Unlight neighbours of node.
973                 // This means setting light of all consequent dimmer nodes
974                 // to 0.
975                 // This also collects the nodes at the border which will spread
976                 // light again into this.
977                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
978
979                 n.setLight(bank, 0, nodemgr);
980         }
981
982         /*
983                 If node lets sunlight through and is under sunlight, it has
984                 sunlight too.
985         */
986         if(node_under_sunlight && nodemgr->get(n).sunlight_propagates)
987         {
988                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
989         }
990
991         /*
992                 Set the node on the map
993         */
994
995         setNode(p, n);
996
997         /*
998                 Add intial metadata
999         */
1000         
1001         std::string metadata_name = nodemgr->get(n).metadata_name;
1002         if(metadata_name != ""){
1003                 NodeMetadata *meta = NodeMetadata::create(metadata_name, m_gamedef);
1004                 if(!meta){
1005                         errorstream<<"Failed to create node metadata \""
1006                                         <<metadata_name<<"\""<<std::endl;
1007                 } else {
1008                         setNodeMetadata(p, meta);
1009                 }
1010         }
1011
1012         /*
1013                 If node is under sunlight and doesn't let sunlight through,
1014                 take all sunlighted nodes under it and clear light from them
1015                 and from where the light has been spread.
1016                 TODO: This could be optimized by mass-unlighting instead
1017                           of looping
1018         */
1019         if(node_under_sunlight && !nodemgr->get(n).sunlight_propagates)
1020         {
1021                 s16 y = p.Y - 1;
1022                 for(;; y--){
1023                         //m_dout<<DTIME<<"y="<<y<<std::endl;
1024                         v3s16 n2pos(p.X, y, p.Z);
1025
1026                         MapNode n2;
1027                         try{
1028                                 n2 = getNode(n2pos);
1029                         }
1030                         catch(InvalidPositionException &e)
1031                         {
1032                                 break;
1033                         }
1034
1035                         if(n2.getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN)
1036                         {
1037                                 unLightNeighbors(LIGHTBANK_DAY,
1038                                                 n2pos, n2.getLight(LIGHTBANK_DAY, nodemgr),
1039                                                 light_sources, modified_blocks);
1040                                 n2.setLight(LIGHTBANK_DAY, 0, nodemgr);
1041                                 setNode(n2pos, n2);
1042                         }
1043                         else
1044                                 break;
1045                 }
1046         }
1047
1048         for(s32 i=0; i<2; i++)
1049         {
1050                 enum LightBank bank = banks[i];
1051
1052                 /*
1053                         Spread light from all nodes that might be capable of doing so
1054                 */
1055                 spreadLight(bank, light_sources, modified_blocks);
1056         }
1057
1058         /*
1059                 Update information about whether day and night light differ
1060         */
1061         for(core::map<v3s16, MapBlock*>::Iterator
1062                         i = modified_blocks.getIterator();
1063                         i.atEnd() == false; i++)
1064         {
1065                 MapBlock *block = i.getNode()->getValue();
1066                 block->updateDayNightDiff();
1067         }
1068
1069         /*
1070                 Add neighboring liquid nodes and the node itself if it is
1071                 liquid (=water node was added) to transform queue.
1072         */
1073         v3s16 dirs[7] = {
1074                 v3s16(0,0,0), // self
1075                 v3s16(0,0,1), // back
1076                 v3s16(0,1,0), // top
1077                 v3s16(1,0,0), // right
1078                 v3s16(0,0,-1), // front
1079                 v3s16(0,-1,0), // bottom
1080                 v3s16(-1,0,0), // left
1081         };
1082         for(u16 i=0; i<7; i++)
1083         {
1084                 try
1085                 {
1086
1087                 v3s16 p2 = p + dirs[i];
1088
1089                 MapNode n2 = getNode(p2);
1090                 if(nodemgr->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)
1091                 {
1092                         m_transforming_liquid.push_back(p2);
1093                 }
1094
1095                 }catch(InvalidPositionException &e)
1096                 {
1097                 }
1098         }
1099 }
1100
1101 /*
1102 */
1103 void Map::removeNodeAndUpdate(v3s16 p,
1104                 core::map<v3s16, MapBlock*> &modified_blocks)
1105 {
1106         INodeDefManager *nodemgr = m_gamedef->ndef();
1107
1108         /*PrintInfo(m_dout);
1109         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1110                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1111
1112         bool node_under_sunlight = true;
1113
1114         v3s16 toppos = p + v3s16(0,1,0);
1115
1116         // Node will be replaced with this
1117         content_t replace_material = CONTENT_AIR;
1118
1119         /*
1120                 If there is a node at top and it doesn't have sunlight,
1121                 there will be no sunlight going down.
1122         */
1123         try{
1124                 MapNode topnode = getNode(toppos);
1125
1126                 if(topnode.getLight(LIGHTBANK_DAY, nodemgr) != LIGHT_SUN)
1127                         node_under_sunlight = false;
1128         }
1129         catch(InvalidPositionException &e)
1130         {
1131         }
1132
1133         core::map<v3s16, bool> light_sources;
1134
1135         enum LightBank banks[] =
1136         {
1137                 LIGHTBANK_DAY,
1138                 LIGHTBANK_NIGHT
1139         };
1140         for(s32 i=0; i<2; i++)
1141         {
1142                 enum LightBank bank = banks[i];
1143
1144                 /*
1145                         Unlight neighbors (in case the node is a light source)
1146                 */
1147                 unLightNeighbors(bank, p,
1148                                 getNode(p).getLight(bank, nodemgr),
1149                                 light_sources, modified_blocks);
1150         }
1151
1152         /*
1153                 Remove node metadata
1154         */
1155
1156         removeNodeMetadata(p);
1157
1158         /*
1159                 Remove the node.
1160                 This also clears the lighting.
1161         */
1162
1163         MapNode n;
1164         n.setContent(replace_material);
1165         setNode(p, n);
1166
1167         for(s32 i=0; i<2; i++)
1168         {
1169                 enum LightBank bank = banks[i];
1170
1171                 /*
1172                         Recalculate lighting
1173                 */
1174                 spreadLight(bank, light_sources, modified_blocks);
1175         }
1176
1177         // Add the block of the removed node to modified_blocks
1178         v3s16 blockpos = getNodeBlockPos(p);
1179         MapBlock * block = getBlockNoCreate(blockpos);
1180         assert(block != NULL);
1181         modified_blocks.insert(blockpos, block);
1182
1183         /*
1184                 If the removed node was under sunlight, propagate the
1185                 sunlight down from it and then light all neighbors
1186                 of the propagated blocks.
1187         */
1188         if(node_under_sunlight)
1189         {
1190                 s16 ybottom = propagateSunlight(p, modified_blocks);
1191                 /*m_dout<<DTIME<<"Node was under sunlight. "
1192                                 "Propagating sunlight";
1193                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1194                 s16 y = p.Y;
1195                 for(; y >= ybottom; y--)
1196                 {
1197                         v3s16 p2(p.X, y, p.Z);
1198                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1199                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1200                                         <<std::endl;*/
1201                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1202                 }
1203         }
1204         else
1205         {
1206                 // Set the lighting of this node to 0
1207                 // TODO: Is this needed? Lighting is cleared up there already.
1208                 try{
1209                         MapNode n = getNode(p);
1210                         n.setLight(LIGHTBANK_DAY, 0, nodemgr);
1211                         setNode(p, n);
1212                 }
1213                 catch(InvalidPositionException &e)
1214                 {
1215                         assert(0);
1216                 }
1217         }
1218
1219         for(s32 i=0; i<2; i++)
1220         {
1221                 enum LightBank bank = banks[i];
1222
1223                 // Get the brightest neighbour node and propagate light from it
1224                 v3s16 n2p = getBrightestNeighbour(bank, p);
1225                 try{
1226                         MapNode n2 = getNode(n2p);
1227                         lightNeighbors(bank, n2p, modified_blocks);
1228                 }
1229                 catch(InvalidPositionException &e)
1230                 {
1231                 }
1232         }
1233
1234         /*
1235                 Update information about whether day and night light differ
1236         */
1237         for(core::map<v3s16, MapBlock*>::Iterator
1238                         i = modified_blocks.getIterator();
1239                         i.atEnd() == false; i++)
1240         {
1241                 MapBlock *block = i.getNode()->getValue();
1242                 block->updateDayNightDiff();
1243         }
1244
1245         /*
1246                 Add neighboring liquid nodes and this node to transform queue.
1247                 (it's vital for the node itself to get updated last.)
1248         */
1249         v3s16 dirs[7] = {
1250                 v3s16(0,0,1), // back
1251                 v3s16(0,1,0), // top
1252                 v3s16(1,0,0), // right
1253                 v3s16(0,0,-1), // front
1254                 v3s16(0,-1,0), // bottom
1255                 v3s16(-1,0,0), // left
1256                 v3s16(0,0,0), // self
1257         };
1258         for(u16 i=0; i<7; i++)
1259         {
1260                 try
1261                 {
1262
1263                 v3s16 p2 = p + dirs[i];
1264
1265                 MapNode n2 = getNode(p2);
1266                 if(nodemgr->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)
1267                 {
1268                         m_transforming_liquid.push_back(p2);
1269                 }
1270
1271                 }catch(InvalidPositionException &e)
1272                 {
1273                 }
1274         }
1275 }
1276
1277 bool Map::addNodeWithEvent(v3s16 p, MapNode n)
1278 {
1279         MapEditEvent event;
1280         event.type = MEET_ADDNODE;
1281         event.p = p;
1282         event.n = n;
1283
1284         bool succeeded = true;
1285         try{
1286                 core::map<v3s16, MapBlock*> modified_blocks;
1287                 addNodeAndUpdate(p, n, modified_blocks);
1288
1289                 // Copy modified_blocks to event
1290                 for(core::map<v3s16, MapBlock*>::Iterator
1291                                 i = modified_blocks.getIterator();
1292                                 i.atEnd()==false; i++)
1293                 {
1294                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1295                 }
1296         }
1297         catch(InvalidPositionException &e){
1298                 succeeded = false;
1299         }
1300
1301         dispatchEvent(&event);
1302
1303         return succeeded;
1304 }
1305
1306 bool Map::removeNodeWithEvent(v3s16 p)
1307 {
1308         MapEditEvent event;
1309         event.type = MEET_REMOVENODE;
1310         event.p = p;
1311
1312         bool succeeded = true;
1313         try{
1314                 core::map<v3s16, MapBlock*> modified_blocks;
1315                 removeNodeAndUpdate(p, modified_blocks);
1316
1317                 // Copy modified_blocks to event
1318                 for(core::map<v3s16, MapBlock*>::Iterator
1319                                 i = modified_blocks.getIterator();
1320                                 i.atEnd()==false; i++)
1321                 {
1322                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1323                 }
1324         }
1325         catch(InvalidPositionException &e){
1326                 succeeded = false;
1327         }
1328
1329         dispatchEvent(&event);
1330
1331         return succeeded;
1332 }
1333
1334 bool Map::dayNightDiffed(v3s16 blockpos)
1335 {
1336         try{
1337                 v3s16 p = blockpos + v3s16(0,0,0);
1338                 MapBlock *b = getBlockNoCreate(p);
1339                 if(b->dayNightDiffed())
1340                         return true;
1341         }
1342         catch(InvalidPositionException &e){}
1343         // Leading edges
1344         try{
1345                 v3s16 p = blockpos + v3s16(-1,0,0);
1346                 MapBlock *b = getBlockNoCreate(p);
1347                 if(b->dayNightDiffed())
1348                         return true;
1349         }
1350         catch(InvalidPositionException &e){}
1351         try{
1352                 v3s16 p = blockpos + v3s16(0,-1,0);
1353                 MapBlock *b = getBlockNoCreate(p);
1354                 if(b->dayNightDiffed())
1355                         return true;
1356         }
1357         catch(InvalidPositionException &e){}
1358         try{
1359                 v3s16 p = blockpos + v3s16(0,0,-1);
1360                 MapBlock *b = getBlockNoCreate(p);
1361                 if(b->dayNightDiffed())
1362                         return true;
1363         }
1364         catch(InvalidPositionException &e){}
1365         // Trailing edges
1366         try{
1367                 v3s16 p = blockpos + v3s16(1,0,0);
1368                 MapBlock *b = getBlockNoCreate(p);
1369                 if(b->dayNightDiffed())
1370                         return true;
1371         }
1372         catch(InvalidPositionException &e){}
1373         try{
1374                 v3s16 p = blockpos + v3s16(0,1,0);
1375                 MapBlock *b = getBlockNoCreate(p);
1376                 if(b->dayNightDiffed())
1377                         return true;
1378         }
1379         catch(InvalidPositionException &e){}
1380         try{
1381                 v3s16 p = blockpos + v3s16(0,0,1);
1382                 MapBlock *b = getBlockNoCreate(p);
1383                 if(b->dayNightDiffed())
1384                         return true;
1385         }
1386         catch(InvalidPositionException &e){}
1387
1388         return false;
1389 }
1390
1391 /*
1392         Updates usage timers
1393 */
1394 void Map::timerUpdate(float dtime, float unload_timeout,
1395                 core::list<v3s16> *unloaded_blocks)
1396 {
1397         bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
1398         
1399         // Profile modified reasons
1400         Profiler modprofiler;
1401         
1402         core::list<v2s16> sector_deletion_queue;
1403         u32 deleted_blocks_count = 0;
1404         u32 saved_blocks_count = 0;
1405         u32 block_count_all = 0;
1406
1407         core::map<v2s16, MapSector*>::Iterator si;
1408
1409         beginSave();
1410         si = m_sectors.getIterator();
1411         for(; si.atEnd() == false; si++)
1412         {
1413                 MapSector *sector = si.getNode()->getValue();
1414
1415                 bool all_blocks_deleted = true;
1416
1417                 core::list<MapBlock*> blocks;
1418                 sector->getBlocks(blocks);
1419                 
1420                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1421                                 i != blocks.end(); i++)
1422                 {
1423                         MapBlock *block = (*i);
1424                         
1425                         block->incrementUsageTimer(dtime);
1426                         
1427                         if(block->getUsageTimer() > unload_timeout)
1428                         {
1429                                 v3s16 p = block->getPos();
1430
1431                                 // Save if modified
1432                                 if(block->getModified() != MOD_STATE_CLEAN
1433                                                 && save_before_unloading)
1434                                 {
1435                                         modprofiler.add(block->getModifiedReason(), 1);
1436                                         saveBlock(block);
1437                                         saved_blocks_count++;
1438                                 }
1439
1440                                 // Delete from memory
1441                                 sector->deleteBlock(block);
1442
1443                                 if(unloaded_blocks)
1444                                         unloaded_blocks->push_back(p);
1445
1446                                 deleted_blocks_count++;
1447                         }
1448                         else
1449                         {
1450                                 all_blocks_deleted = false;
1451                                 block_count_all++;
1452                         }
1453                 }
1454
1455                 if(all_blocks_deleted)
1456                 {
1457                         sector_deletion_queue.push_back(si.getNode()->getKey());
1458                 }
1459         }
1460         endSave();
1461         
1462         // Finally delete the empty sectors
1463         deleteSectors(sector_deletion_queue);
1464         
1465         if(deleted_blocks_count != 0)
1466         {
1467                 PrintInfo(infostream); // ServerMap/ClientMap:
1468                 infostream<<"Unloaded "<<deleted_blocks_count
1469                                 <<" blocks from memory";
1470                 if(save_before_unloading)
1471                         infostream<<", of which "<<saved_blocks_count<<" were written";
1472                 infostream<<", "<<block_count_all<<" blocks in memory";
1473                 infostream<<"."<<std::endl;
1474                 if(saved_blocks_count != 0){
1475                         PrintInfo(infostream); // ServerMap/ClientMap:
1476                         infostream<<"Blocks modified by: "<<std::endl;
1477                         modprofiler.print(infostream);
1478                 }
1479         }
1480 }
1481
1482 void Map::deleteSectors(core::list<v2s16> &list)
1483 {
1484         core::list<v2s16>::Iterator j;
1485         for(j=list.begin(); j!=list.end(); j++)
1486         {
1487                 MapSector *sector = m_sectors[*j];
1488                 // If sector is in sector cache, remove it from there
1489                 if(m_sector_cache == sector)
1490                         m_sector_cache = NULL;
1491                 // Remove from map and delete
1492                 m_sectors.remove(*j);
1493                 delete sector;
1494         }
1495 }
1496
1497 #if 0
1498 void Map::unloadUnusedData(float timeout,
1499                 core::list<v3s16> *deleted_blocks)
1500 {
1501         core::list<v2s16> sector_deletion_queue;
1502         u32 deleted_blocks_count = 0;
1503         u32 saved_blocks_count = 0;
1504
1505         core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
1506         for(; si.atEnd() == false; si++)
1507         {
1508                 MapSector *sector = si.getNode()->getValue();
1509
1510                 bool all_blocks_deleted = true;
1511
1512                 core::list<MapBlock*> blocks;
1513                 sector->getBlocks(blocks);
1514                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1515                                 i != blocks.end(); i++)
1516                 {
1517                         MapBlock *block = (*i);
1518                         
1519                         if(block->getUsageTimer() > timeout)
1520                         {
1521                                 // Save if modified
1522                                 if(block->getModified() != MOD_STATE_CLEAN)
1523                                 {
1524                                         saveBlock(block);
1525                                         saved_blocks_count++;
1526                                 }
1527                                 // Delete from memory
1528                                 sector->deleteBlock(block);
1529                                 deleted_blocks_count++;
1530                         }
1531                         else
1532                         {
1533                                 all_blocks_deleted = false;
1534                         }
1535                 }
1536
1537                 if(all_blocks_deleted)
1538                 {
1539                         sector_deletion_queue.push_back(si.getNode()->getKey());
1540                 }
1541         }
1542
1543         deleteSectors(sector_deletion_queue);
1544
1545         infostream<<"Map: Unloaded "<<deleted_blocks_count<<" blocks from memory"
1546                         <<", of which "<<saved_blocks_count<<" were wr."
1547                         <<std::endl;
1548
1549         //return sector_deletion_queue.getSize();
1550         //return deleted_blocks_count;
1551 }
1552 #endif
1553
1554 void Map::PrintInfo(std::ostream &out)
1555 {
1556         out<<"Map: ";
1557 }
1558
1559 #define WATER_DROP_BOOST 4
1560
1561 enum NeighborType {
1562         NEIGHBOR_UPPER,
1563         NEIGHBOR_SAME_LEVEL,
1564         NEIGHBOR_LOWER
1565 };
1566 struct NodeNeighbor {
1567         MapNode n;
1568         NeighborType t;
1569         v3s16 p;
1570 };
1571
1572 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1573 {
1574         INodeDefManager *nodemgr = m_gamedef->ndef();
1575
1576         DSTACK(__FUNCTION_NAME);
1577         //TimeTaker timer("transformLiquids()");
1578
1579         u32 loopcount = 0;
1580         u32 initial_size = m_transforming_liquid.size();
1581
1582         /*if(initial_size != 0)
1583                 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1584
1585         // list of nodes that due to viscosity have not reached their max level height
1586         UniqueQueue<v3s16> must_reflow;
1587         
1588         // List of MapBlocks that will require a lighting update (due to lava)
1589         core::map<v3s16, MapBlock*> lighting_modified_blocks;
1590
1591         while(m_transforming_liquid.size() != 0)
1592         {
1593                 // This should be done here so that it is done when continue is used
1594                 if(loopcount >= initial_size * 3)
1595                         break;
1596                 loopcount++;
1597
1598                 /*
1599                         Get a queued transforming liquid node
1600                 */
1601                 v3s16 p0 = m_transforming_liquid.pop_front();
1602
1603                 MapNode n0 = getNodeNoEx(p0);
1604
1605                 /*
1606                         Collect information about current node
1607                  */
1608                 s8 liquid_level = -1;
1609                 u8 liquid_kind = CONTENT_IGNORE;
1610                 LiquidType liquid_type = nodemgr->get(n0).liquid_type;
1611                 switch (liquid_type) {
1612                         case LIQUID_SOURCE:
1613                                 liquid_level = LIQUID_LEVEL_SOURCE;
1614                                 liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing);
1615                                 break;
1616                         case LIQUID_FLOWING:
1617                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
1618                                 liquid_kind = n0.getContent();
1619                                 break;
1620                         case LIQUID_NONE:
1621                                 // if this is an air node, it *could* be transformed into a liquid. otherwise,
1622                                 // continue with the next node.
1623                                 if (n0.getContent() != CONTENT_AIR)
1624                                         continue;
1625                                 liquid_kind = CONTENT_AIR;
1626                                 break;
1627                 }
1628
1629                 /*
1630                         Collect information about the environment
1631                  */
1632                 const v3s16 *dirs = g_6dirs;
1633                 NodeNeighbor sources[6]; // surrounding sources
1634                 int num_sources = 0;
1635                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
1636                 int num_flows = 0;
1637                 NodeNeighbor airs[6]; // surrounding air
1638                 int num_airs = 0;
1639                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
1640                 int num_neutrals = 0;
1641                 bool flowing_down = false;
1642                 for (u16 i = 0; i < 6; i++) {
1643                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1644                         switch (i) {
1645                                 case 1:
1646                                         nt = NEIGHBOR_UPPER;
1647                                         break;
1648                                 case 4:
1649                                         nt = NEIGHBOR_LOWER;
1650                                         break;
1651                         }
1652                         v3s16 npos = p0 + dirs[i];
1653                         NodeNeighbor nb = {getNodeNoEx(npos), nt, npos};
1654                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
1655                                 case LIQUID_NONE:
1656                                         if (nb.n.getContent() == CONTENT_AIR) {
1657                                                 airs[num_airs++] = nb;
1658                                                 // if the current node is a water source the neighbor
1659                                                 // should be enqueded for transformation regardless of whether the
1660                                                 // current node changes or not.
1661                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
1662                                                         m_transforming_liquid.push_back(npos);
1663                                                 // if the current node happens to be a flowing node, it will start to flow down here.
1664                                                 if (nb.t == NEIGHBOR_LOWER) {
1665                                                         flowing_down = true;
1666                                                 }
1667                                         } else {
1668                                                 neutrals[num_neutrals++] = nb;
1669                                         }
1670                                         break;
1671                                 case LIQUID_SOURCE:
1672                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter 
1673                                         if (liquid_kind == CONTENT_AIR)
1674                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
1675                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
1676                                                 neutrals[num_neutrals++] = nb;
1677                                         } else {
1678                                                 // Do not count bottom source, it will screw things up
1679                                                 if(dirs[i].Y != -1)
1680                                                         sources[num_sources++] = nb;
1681                                         }
1682                                         break;
1683                                 case LIQUID_FLOWING:
1684                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1685                                         if (liquid_kind == CONTENT_AIR)
1686                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
1687                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
1688                                                 neutrals[num_neutrals++] = nb;
1689                                         } else {
1690                                                 flows[num_flows++] = nb;
1691                                                 if (nb.t == NEIGHBOR_LOWER)
1692                                                         flowing_down = true;
1693                                         }
1694                                         break;
1695                         }
1696                 }
1697
1698                 /*
1699                         decide on the type (and possibly level) of the current node
1700                  */
1701                 content_t new_node_content;
1702                 s8 new_node_level = -1;
1703                 s8 max_node_level = -1;
1704                 if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
1705                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1706                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1707                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1708                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
1709                 } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
1710                         // liquid_kind is set properly, see above
1711                         new_node_content = liquid_kind;
1712                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
1713                 } else {
1714                         // no surrounding sources, so get the maximum level that can flow into this node
1715                         for (u16 i = 0; i < num_flows; i++) {
1716                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1717                                 switch (flows[i].t) {
1718                                         case NEIGHBOR_UPPER:
1719                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
1720                                                         max_node_level = LIQUID_LEVEL_MAX;
1721                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1722                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
1723                                                 } else if (nb_liquid_level > max_node_level)
1724                                                         max_node_level = nb_liquid_level;
1725                                                 break;
1726                                         case NEIGHBOR_LOWER:
1727                                                 break;
1728                                         case NEIGHBOR_SAME_LEVEL:
1729                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1730                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
1731                                                         max_node_level = nb_liquid_level - 1;
1732                                                 }
1733                                                 break;
1734                                 }
1735                         }
1736
1737                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
1738                         if (viscosity > 1 && max_node_level != liquid_level) {
1739                                 // amount to gain, limited by viscosity
1740                                 // must be at least 1 in absolute value
1741                                 s8 level_inc = max_node_level - liquid_level;
1742                                 if (level_inc < -viscosity || level_inc > viscosity)
1743                                         new_node_level = liquid_level + level_inc/viscosity;
1744                                 else if (level_inc < 0)
1745                                         new_node_level = liquid_level - 1;
1746                                 else if (level_inc > 0)
1747                                         new_node_level = liquid_level + 1;
1748                                 if (new_node_level != max_node_level)
1749                                         must_reflow.push_back(p0);
1750                         } else
1751                                 new_node_level = max_node_level;
1752
1753                         if (new_node_level >= 0)
1754                                 new_node_content = liquid_kind;
1755                         else
1756                                 new_node_content = CONTENT_AIR;
1757
1758                 }
1759
1760                 /*
1761                         check if anything has changed. if not, just continue with the next node.
1762                  */
1763                 if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1764                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1765                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1766                                                                                  == flowing_down)))
1767                         continue;
1768
1769
1770                 /*
1771                         update the current node
1772                  */
1773                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1774                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
1775                         // set level to last 3 bits, flowing down bit to 4th bit
1776                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1777                 } else {
1778                         // set the liquid level and flow bit to 0
1779                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1780                 }
1781                 n0.setContent(new_node_content);
1782                 setNode(p0, n0);
1783                 v3s16 blockpos = getNodeBlockPos(p0);
1784                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1785                 if(block != NULL) {
1786                         modified_blocks.insert(blockpos, block);
1787                         // If node emits light, MapBlock requires lighting update
1788                         if(nodemgr->get(n0).light_source != 0)
1789                                 lighting_modified_blocks[block->getPos()] = block;
1790                 }
1791
1792                 /*
1793                         enqueue neighbors for update if neccessary
1794                  */
1795                 switch (nodemgr->get(n0.getContent()).liquid_type) {
1796                         case LIQUID_SOURCE:
1797                         case LIQUID_FLOWING:
1798                                 // make sure source flows into all neighboring nodes
1799                                 for (u16 i = 0; i < num_flows; i++)
1800                                         if (flows[i].t != NEIGHBOR_UPPER)
1801                                                 m_transforming_liquid.push_back(flows[i].p);
1802                                 for (u16 i = 0; i < num_airs; i++)
1803                                         if (airs[i].t != NEIGHBOR_UPPER)
1804                                                 m_transforming_liquid.push_back(airs[i].p);
1805                                 break;
1806                         case LIQUID_NONE:
1807                                 // this flow has turned to air; neighboring flows might need to do the same
1808                                 for (u16 i = 0; i < num_flows; i++)
1809                                         m_transforming_liquid.push_back(flows[i].p);
1810                                 break;
1811                 }
1812         }
1813         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1814         while (must_reflow.size() > 0)
1815                 m_transforming_liquid.push_back(must_reflow.pop_front());
1816         updateLighting(lighting_modified_blocks, modified_blocks);
1817 }
1818
1819 NodeMetadata* Map::getNodeMetadata(v3s16 p)
1820 {
1821         v3s16 blockpos = getNodeBlockPos(p);
1822         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1823         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1824         if(!block){
1825                 infostream<<"Map::getNodeMetadata(): Need to emerge "
1826                                 <<PP(blockpos)<<std::endl;
1827                 block = emergeBlock(blockpos, false);
1828         }
1829         if(!block)
1830         {
1831                 infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
1832                                 <<std::endl;
1833                 return NULL;
1834         }
1835         NodeMetadata *meta = block->m_node_metadata->get(p_rel);
1836         return meta;
1837 }
1838
1839 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1840 {
1841         v3s16 blockpos = getNodeBlockPos(p);
1842         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1843         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1844         if(!block){
1845                 infostream<<"Map::setNodeMetadata(): Need to emerge "
1846                                 <<PP(blockpos)<<std::endl;
1847                 block = emergeBlock(blockpos, false);
1848         }
1849         if(!block)
1850         {
1851                 infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
1852                                 <<std::endl;
1853                 return;
1854         }
1855         block->m_node_metadata->set(p_rel, meta);
1856 }
1857
1858 void Map::removeNodeMetadata(v3s16 p)
1859 {
1860         v3s16 blockpos = getNodeBlockPos(p);
1861         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1862         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1863         if(block == NULL)
1864         {
1865                 infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1866                                 <<std::endl;
1867                 return;
1868         }
1869         block->m_node_metadata->remove(p_rel);
1870 }
1871
1872 void Map::nodeMetadataStep(float dtime,
1873                 core::map<v3s16, MapBlock*> &changed_blocks)
1874 {
1875         /*
1876                 NOTE:
1877                 Currently there is no way to ensure that all the necessary
1878                 blocks are loaded when this is run. (They might get unloaded)
1879                 NOTE: ^- Actually, that might not be so. In a quick test it
1880                 reloaded a block with a furnace when I walked back to it from
1881                 a distance.
1882         */
1883         core::map<v2s16, MapSector*>::Iterator si;
1884         si = m_sectors.getIterator();
1885         for(; si.atEnd() == false; si++)
1886         {
1887                 MapSector *sector = si.getNode()->getValue();
1888                 core::list< MapBlock * > sectorblocks;
1889                 sector->getBlocks(sectorblocks);
1890                 core::list< MapBlock * >::Iterator i;
1891                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1892                 {
1893                         MapBlock *block = *i;
1894                         bool changed = block->m_node_metadata->step(dtime);
1895                         if(changed)
1896                                 changed_blocks[block->getPos()] = block;
1897                 }
1898         }
1899 }
1900
1901 /*
1902         ServerMap
1903 */
1904
1905 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef):
1906         Map(dout_server, gamedef),
1907         m_seed(0),
1908         m_map_metadata_changed(true),
1909         m_database(NULL),
1910         m_database_read(NULL),
1911         m_database_write(NULL)
1912 {
1913         verbosestream<<__FUNCTION_NAME<<std::endl;
1914
1915         //m_chunksize = 8; // Takes a few seconds
1916
1917         if (g_settings->get("fixed_map_seed").empty())
1918         {
1919                 m_seed = (((u64)(myrand()%0xffff)<<0)
1920                                 + ((u64)(myrand()%0xffff)<<16)
1921                                 + ((u64)(myrand()%0xffff)<<32)
1922                                 + ((u64)(myrand()%0xffff)<<48));
1923         }
1924         else
1925         {
1926                 m_seed = g_settings->getU64("fixed_map_seed");
1927         }
1928
1929         /*
1930                 Experimental and debug stuff
1931         */
1932
1933         {
1934         }
1935
1936         /*
1937                 Try to load map; if not found, create a new one.
1938         */
1939
1940         m_savedir = savedir;
1941         m_map_saving_enabled = false;
1942
1943         try
1944         {
1945                 // If directory exists, check contents and load if possible
1946                 if(fs::PathExists(m_savedir))
1947                 {
1948                         // If directory is empty, it is safe to save into it.
1949                         if(fs::GetDirListing(m_savedir).size() == 0)
1950                         {
1951                                 infostream<<"ServerMap: Empty save directory is valid."
1952                                                 <<std::endl;
1953                                 m_map_saving_enabled = true;
1954                         }
1955                         else
1956                         {
1957                                 try{
1958                                         // Load map metadata (seed, chunksize)
1959                                         loadMapMeta();
1960                                 }
1961                                 catch(FileNotGoodException &e){
1962                                         infostream<<"WARNING: Could not load map metadata"
1963                                                         //<<" Disabling chunk-based generator."
1964                                                         <<std::endl;
1965                                         //m_chunksize = 0;
1966                                 }
1967
1968                                 infostream<<"ServerMap: Successfully loaded map "
1969                                                 <<"metadata from "<<savedir
1970                                                 <<", assuming valid save directory."
1971                                                 <<" seed="<<m_seed<<"."
1972                                                 <<std::endl;
1973
1974                                 m_map_saving_enabled = true;
1975                                 // Map loaded, not creating new one
1976                                 return;
1977                         }
1978                 }
1979                 // If directory doesn't exist, it is safe to save to it
1980                 else{
1981                         m_map_saving_enabled = true;
1982                 }
1983         }
1984         catch(std::exception &e)
1985         {
1986                 infostream<<"WARNING: ServerMap: Failed to load map from "<<savedir
1987                                 <<", exception: "<<e.what()<<std::endl;
1988                 infostream<<"Please remove the map or fix it."<<std::endl;
1989                 infostream<<"WARNING: Map saving will be disabled."<<std::endl;
1990         }
1991
1992         infostream<<"Initializing new map."<<std::endl;
1993
1994         // Create zero sector
1995         emergeSector(v2s16(0,0));
1996
1997         // Initially write whole map
1998         save(MOD_STATE_CLEAN);
1999 }
2000
2001 ServerMap::~ServerMap()
2002 {
2003         verbosestream<<__FUNCTION_NAME<<std::endl;
2004
2005         try
2006         {
2007                 if(m_map_saving_enabled)
2008                 {
2009                         // Save only changed parts
2010                         save(MOD_STATE_WRITE_AT_UNLOAD);
2011                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
2012                 }
2013                 else
2014                 {
2015                         infostream<<"ServerMap: Map not saved"<<std::endl;
2016                 }
2017         }
2018         catch(std::exception &e)
2019         {
2020                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
2021                                 <<", exception: "<<e.what()<<std::endl;
2022         }
2023
2024         /*
2025                 Close database if it was opened
2026         */
2027         if(m_database_read)
2028                 sqlite3_finalize(m_database_read);
2029         if(m_database_write)
2030                 sqlite3_finalize(m_database_write);
2031         if(m_database)
2032                 sqlite3_close(m_database);
2033
2034 #if 0
2035         /*
2036                 Free all MapChunks
2037         */
2038         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2039         for(; i.atEnd() == false; i++)
2040         {
2041                 MapChunk *chunk = i.getNode()->getValue();
2042                 delete chunk;
2043         }
2044 #endif
2045 }
2046
2047 void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
2048 {
2049         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2050         if(enable_mapgen_debug_info)
2051                 infostream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2052                                 <<blockpos.Z<<")"<<std::endl;
2053         
2054         // Do nothing if not inside limits (+-1 because of neighbors)
2055         if(blockpos_over_limit(blockpos - v3s16(1,1,1)) ||
2056                 blockpos_over_limit(blockpos + v3s16(1,1,1)))
2057         {
2058                 data->no_op = true;
2059                 return;
2060         }
2061         
2062         data->no_op = false;
2063         data->seed = m_seed;
2064         data->blockpos = blockpos;
2065         data->nodedef = m_gamedef->ndef();
2066
2067         /*
2068                 Create the whole area of this and the neighboring blocks
2069         */
2070         {
2071                 //TimeTaker timer("initBlockMake() create area");
2072                 
2073                 for(s16 x=-1; x<=1; x++)
2074                 for(s16 z=-1; z<=1; z++)
2075                 {
2076                         v2s16 sectorpos(blockpos.X+x, blockpos.Z+z);
2077                         // Sector metadata is loaded from disk if not already loaded.
2078                         ServerMapSector *sector = createSector(sectorpos);
2079                         assert(sector);
2080
2081                         for(s16 y=-1; y<=1; y++)
2082                         {
2083                                 v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z);
2084                                 //MapBlock *block = createBlock(p);
2085                                 // 1) get from memory, 2) load from disk
2086                                 MapBlock *block = emergeBlock(p, false);
2087                                 // 3) create a blank one
2088                                 if(block == NULL)
2089                                 {
2090                                         block = createBlock(p);
2091
2092                                         /*
2093                                                 Block gets sunlight if this is true.
2094
2095                                                 Refer to the map generator heuristics.
2096                                         */
2097                                         bool ug = mapgen::block_is_underground(data->seed, p);
2098                                         block->setIsUnderground(ug);
2099                                 }
2100
2101                                 // Lighting will not be valid after make_chunk is called
2102                                 block->setLightingExpired(true);
2103                                 // Lighting will be calculated
2104                                 //block->setLightingExpired(false);
2105                         }
2106                 }
2107         }
2108         
2109         /*
2110                 Now we have a big empty area.
2111
2112                 Make a ManualMapVoxelManipulator that contains this and the
2113                 neighboring blocks
2114         */
2115         
2116         // The area that contains this block and it's neighbors
2117         v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
2118         v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
2119         
2120         data->vmanip = new ManualMapVoxelManipulator(this);
2121         //data->vmanip->setMap(this);
2122
2123         // Add the area
2124         {
2125                 //TimeTaker timer("initBlockMake() initialEmerge");
2126                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2127         }
2128
2129         // Data is ready now.
2130 }
2131
2132 MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
2133                 core::map<v3s16, MapBlock*> &changed_blocks)
2134 {
2135         v3s16 blockpos = data->blockpos;
2136         /*infostream<<"finishBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2137                         <<blockpos.Z<<")"<<std::endl;*/
2138
2139         if(data->no_op)
2140         {
2141                 //infostream<<"finishBlockMake(): no-op"<<std::endl;
2142                 return NULL;
2143         }
2144
2145         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2146
2147         /*infostream<<"Resulting vmanip:"<<std::endl;
2148         data->vmanip.print(infostream);*/
2149
2150         // Make sure affected blocks are loaded
2151         for(s16 x=-1; x<=1; x++)
2152         for(s16 z=-1; z<=1; z++)
2153         for(s16 y=-1; y<=1; y++)
2154         {
2155                 v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z);
2156                 // Load from disk if not already in memory
2157                 emergeBlock(p, false);
2158         }
2159
2160         /*
2161                 Blit generated stuff to map
2162                 NOTE: blitBackAll adds nearly everything to changed_blocks
2163         */
2164         {
2165                 // 70ms @cs=8
2166                 //TimeTaker timer("finishBlockMake() blitBackAll");
2167                 data->vmanip->blitBackAll(&changed_blocks);
2168         }
2169
2170         if(enable_mapgen_debug_info)
2171                 infostream<<"finishBlockMake: changed_blocks.size()="
2172                                 <<changed_blocks.size()<<std::endl;
2173
2174         /*
2175                 Copy transforming liquid information
2176         */
2177         while(data->transforming_liquid.size() > 0)
2178         {
2179                 v3s16 p = data->transforming_liquid.pop_front();
2180                 m_transforming_liquid.push_back(p);
2181         }
2182         
2183         /*
2184                 Get central block
2185         */
2186         MapBlock *block = getBlockNoCreateNoEx(data->blockpos);
2187         assert(block);
2188
2189         /*
2190                 Set is_underground flag for lighting with sunlight.
2191
2192                 Refer to map generator heuristics.
2193
2194                 NOTE: This is done in initChunkMake
2195         */
2196         //block->setIsUnderground(mapgen::block_is_underground(data->seed, blockpos));
2197
2198
2199         /*
2200                 Add sunlight to central block.
2201                 This makes in-dark-spawning monsters to not flood the whole thing.
2202                 Do not spread the light, though.
2203         */
2204         /*core::map<v3s16, bool> light_sources;
2205         bool black_air_left = false;
2206         block->propagateSunlight(light_sources, true, &black_air_left);*/
2207
2208         /*
2209                 NOTE: Lighting and object adding shouldn't really be here, but
2210                 lighting is a bit tricky to move properly to makeBlock.
2211                 TODO: Do this the right way anyway, that is, move it to makeBlock.
2212                       - There needs to be some way for makeBlock to report back if
2213                             the lighting update is going further down because of the
2214                                 new block blocking light
2215         */
2216
2217         /*
2218                 Update lighting
2219                 NOTE: This takes ~60ms, TODO: Investigate why
2220         */
2221         {
2222                 TimeTaker t("finishBlockMake lighting update");
2223
2224                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2225 #if 1
2226                 // Center block
2227                 lighting_update_blocks.insert(block->getPos(), block);
2228
2229                 /*{
2230                         s16 x = 0;
2231                         s16 z = 0;
2232                         v3s16 p = block->getPos()+v3s16(x,1,z);
2233                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2234                 }*/
2235 #endif
2236 #if 0
2237                 // All modified blocks
2238                 // NOTE: Should this be done? If this is not done, then the lighting
2239                 // of the others will be updated in a different place, one by one, i
2240                 // think... or they might not? Well, at least they are left marked as
2241                 // "lighting expired"; it seems that is not handled at all anywhere,
2242                 // so enabling this will slow it down A LOT because otherwise it
2243                 // would not do this at all. This causes the black trees.
2244                 for(core::map<v3s16, MapBlock*>::Iterator
2245                                 i = changed_blocks.getIterator();
2246                                 i.atEnd() == false; i++)
2247                 {
2248                         lighting_update_blocks.insert(i.getNode()->getKey(),
2249                                         i.getNode()->getValue());
2250                 }
2251                 /*// Also force-add all the upmost blocks for proper sunlight
2252                 for(s16 x=-1; x<=1; x++)
2253                 for(s16 z=-1; z<=1; z++)
2254                 {
2255                         v3s16 p = block->getPos()+v3s16(x,1,z);
2256                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2257                 }*/
2258 #endif
2259                 updateLighting(lighting_update_blocks, changed_blocks);
2260                 
2261                 /*
2262                         Set lighting to non-expired state in all of them.
2263                         This is cheating, but it is not fast enough if all of them
2264                         would actually be updated.
2265                 */
2266                 for(s16 x=-1; x<=1; x++)
2267                 for(s16 y=-1; y<=1; y++)
2268                 for(s16 z=-1; z<=1; z++)
2269                 {
2270                         v3s16 p = block->getPos()+v3s16(x,y,z);
2271                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2272                 }
2273
2274                 if(enable_mapgen_debug_info == false)
2275                         t.stop(true); // Hide output
2276         }
2277
2278         /*
2279                 Add random objects to block
2280         */
2281         mapgen::add_random_objects(block);
2282
2283         /*
2284                 Go through changed blocks
2285         */
2286         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
2287                         i.atEnd() == false; i++)
2288         {
2289                 MapBlock *block = i.getNode()->getValue();
2290                 assert(block);
2291                 /*
2292                         Update day/night difference cache of the MapBlocks
2293                 */
2294                 block->updateDayNightDiff();
2295                 /*
2296                         Set block as modified
2297                 */
2298                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2299                                 "finishBlockMake updateDayNightDiff");
2300         }
2301
2302         /*
2303                 Set central block as generated
2304         */
2305         block->setGenerated(true);
2306         
2307         /*
2308                 Save changed parts of map
2309                 NOTE: Will be saved later.
2310         */
2311         //save(MOD_STATE_WRITE_AT_UNLOAD);
2312
2313         /*infostream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
2314                         <<blockpos.Z<<")"<<std::endl;*/
2315 #if 0
2316         if(enable_mapgen_debug_info)
2317         {
2318                 /*
2319                         Analyze resulting blocks
2320                 */
2321                 for(s16 x=-1; x<=1; x++)
2322                 for(s16 y=-1; y<=1; y++)
2323                 for(s16 z=-1; z<=1; z++)
2324                 {
2325                         v3s16 p = block->getPos()+v3s16(x,y,z);
2326                         MapBlock *block = getBlockNoCreateNoEx(p);
2327                         char spos[20];
2328                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2329                         infostream<<"Generated "<<spos<<": "
2330                                         <<analyze_block(block)<<std::endl;
2331                 }
2332         }
2333 #endif
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