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