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