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