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