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