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