]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
Add and implement setting max_clearobjects_extra_loaded_blocks.
[dragonfireclient.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         while (m_transforming_liquid.size() > 0)
1655         {
1656                 // This should be done here so that it is done when continue is used
1657                 if (loopcount >= initial_size || loopcount >= 1000)
1658                         break;
1659                 loopcount++;
1660                 /*
1661                         Get a queued transforming liquid node
1662                 */
1663                 v3s16 p0 = m_transforming_liquid.pop_front();
1664                 u16 total_level = 0;
1665                 // surrounding flowing liquid nodes
1666                 NodeNeighbor neighbors[7]; 
1667                 // current level of every block
1668                 s8 liquid_levels[7] = {-1, -1, -1, -1, -1, -1, -1};
1669                  // target levels
1670                 s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1};
1671                 s8 can_liquid_same_level = 0;
1672                 content_t liquid_kind = CONTENT_IGNORE;
1673                 content_t liquid_kind_flowing = CONTENT_IGNORE;
1674                 /*
1675                         Collect information about the environment
1676                  */
1677                 const v3s16 *dirs = g_7dirs;
1678                 for (u16 i = 0; i < 7; i++) {
1679                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1680                         switch (i) {
1681                                 case D_TOP:
1682                                         nt = NEIGHBOR_UPPER;
1683                                         break;
1684                                 case D_BOTTOM:
1685                                         nt = NEIGHBOR_LOWER;
1686                                         break;
1687                         }
1688                         v3s16 npos = p0 + dirs[i];
1689
1690                         neighbors[i].n = getNodeNoEx(npos);
1691                         neighbors[i].t = nt;
1692                         neighbors[i].p = npos;
1693                         neighbors[i].l = 0;
1694                         neighbors[i].i = 0;
1695                         NodeNeighbor & nb = neighbors[i];
1696
1697                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
1698                                 case LIQUID_NONE:
1699                                         if (nb.n.getContent() == CONTENT_AIR) {
1700                                                 liquid_levels[i] = 0;
1701                                                 nb.l = 1;
1702                                         }
1703                                         break;
1704                                 case LIQUID_SOURCE:
1705                                         // if this node is not (yet) of a liquid type,
1706                                         // choose the first liquid type we encounter
1707                                         if (liquid_kind_flowing == CONTENT_IGNORE)
1708                                                 liquid_kind_flowing = nodemgr->getId(
1709                                                         nodemgr->get(nb.n).liquid_alternative_flowing);
1710                                         if (liquid_kind == CONTENT_IGNORE)
1711                                                 liquid_kind = nb.n.getContent();
1712                                         if (nb.n.getContent() == liquid_kind) {
1713                                                 liquid_levels[i] = LIQUID_LEVEL_SOURCE;
1714                                                 nb.l = 1;
1715                                                 nb.i = (nb.n.param2 & LIQUID_INFINITY_MASK);
1716                                         }
1717                                         break;
1718                                 case LIQUID_FLOWING:
1719                                         // if this node is not (yet) of a liquid type,
1720                                         // choose the first liquid type we encounter
1721                                         if (liquid_kind_flowing == CONTENT_IGNORE)
1722                                                 liquid_kind_flowing = nb.n.getContent();
1723                                         if (liquid_kind == CONTENT_IGNORE)
1724                                                 liquid_kind = nodemgr->getId(
1725                                                         nodemgr->get(nb.n).liquid_alternative_source);
1726                                         if (nb.n.getContent() == liquid_kind_flowing) {
1727                                                 liquid_levels[i] = (nb.n.param2 & LIQUID_LEVEL_MASK);
1728                                                 nb.l = 1;
1729                                         }
1730                                         break;
1731                         }
1732                         
1733                         if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL)
1734                                 ++can_liquid_same_level;
1735                         if (liquid_levels[i] > 0)
1736                                 total_level += liquid_levels[i];
1737
1738                         /*
1739                         infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c="
1740                         << nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1="
1741                         << (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt="
1742                         << nodemgr->get(nb.n.getContent()).liquid_type
1743                         //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing
1744                         << " l="<< nb.l << " inf="<< nb.i << " nlevel=" << (int)liquid_levels[i]
1745                         << " tlevel=" << (int)total_level << " cansame="
1746                         << (int)can_liquid_same_level << std::endl;
1747                         */
1748                 }
1749
1750                 if (liquid_kind == CONTENT_IGNORE ||
1751                         !neighbors[D_SELF].l ||
1752                         total_level <= 0)
1753                         continue;
1754
1755                 // fill bottom block
1756                 if (neighbors[D_BOTTOM].l) {
1757                         liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ?
1758                                 LIQUID_LEVEL_SOURCE : total_level;
1759                         total_level -= liquid_levels_want[D_BOTTOM];
1760                 }
1761
1762                 //relax up
1763                 if (relax && ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) && liquid_levels[D_TOP] == 0 &&
1764                         liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE &&
1765                         total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level-
1766                         (can_liquid_same_level - relax) &&
1767                         can_liquid_same_level >= relax + 1) { 
1768                         total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level; 
1769                 }
1770
1771                 // prevent lakes in air above unloaded blocks
1772                 if (liquid_levels[D_TOP] == 0 && (p0.Y > water_level || !fast_flood) && neighbors[D_BOTTOM].n.getContent() == CONTENT_IGNORE) {
1773                         --total_level;
1774                 }
1775
1776                 // calculate self level 5 blocks
1777                 u8 want_level = 
1778                           total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level
1779                         ? LIQUID_LEVEL_SOURCE 
1780                         : total_level / can_liquid_same_level;
1781                 total_level -= want_level * can_liquid_same_level;
1782
1783                 //relax down
1784                 if (relax && p0.Y == water_level + 1 && liquid_levels[D_TOP] == 0 &&
1785                         liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 &&
1786                         total_level <= (can_liquid_same_level - relax) &&
1787                         can_liquid_same_level >= relax + 1) {
1788                         total_level = 0;
1789                 }
1790
1791                 for (u16 ii = D_SELF; ii < D_TOP; ++ii) { // fill only same level
1792                         if (!neighbors[ii].l)
1793                                 continue;
1794                         liquid_levels_want[ii] = want_level;
1795                         if (liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE && total_level > 0
1796                                 && liquid_levels[ii] > liquid_levels_want[ii]
1797                                 ) {
1798                                 ++liquid_levels_want[ii];
1799                                 --total_level;
1800                         }
1801                 }
1802
1803                 for (u16 ii = 0; ii < 7; ++ii) {
1804                         if (total_level < 1) break;
1805                         if (liquid_levels_want[ii] >= 0 &&
1806                                 liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE) {
1807                                 ++liquid_levels_want[ii];
1808                                 --total_level;
1809                         }
1810                 }
1811
1812                 // fill top block if can
1813                 if (neighbors[D_TOP].l) {
1814                         liquid_levels_want[D_TOP] = total_level > LIQUID_LEVEL_SOURCE ?
1815                                 LIQUID_LEVEL_SOURCE : total_level;
1816                         total_level -= liquid_levels_want[D_TOP];
1817                 }
1818
1819                 for (u16 ii = 0; ii < 7; ii++) // infinity and cave flood optimization
1820                         if (    neighbors[ii].i ||
1821                                 (liquid_levels_want[ii] >= 0 &&
1822                                  (fast_flood && p0.Y < water_level &&
1823                                   (initial_size >= 1000
1824                                    && ii != D_TOP
1825                                    && want_level >= LIQUID_LEVEL_SOURCE/4
1826                                    && can_liquid_same_level >= 5
1827                                    && liquid_levels[D_TOP] >= LIQUID_LEVEL_SOURCE))))
1828                                 liquid_levels_want[ii] = LIQUID_LEVEL_SOURCE;
1829
1830                 /*
1831                 if (total_level > 0) //|| flowed != volume)
1832                         infostream <<" AFTER level=" << (int)total_level 
1833                         //<< " flowed="<<flowed<< " volume=" << volume
1834                         << " wantsame="<<(int)want_level<< " top="
1835                         << (int)liquid_levels_want[D_TOP]<< " topwas="
1836                         << (int)liquid_levels[D_TOP]<< " bot="
1837                         << (int)liquid_levels_want[D_BOTTOM]<<std::endl;
1838                 */
1839
1840                 u8 changed = 0;
1841                 for (u16 i = 0; i < 7; i++) {
1842                         if (liquid_levels_want[i] < 0 || !neighbors[i].l) 
1843                                 continue;
1844                         MapNode & n0 = neighbors[i].n;
1845                         p0 = neighbors[i].p;
1846                         /*
1847                                 decide on the type (and possibly level) of the current node
1848                         */
1849                         content_t new_node_content;
1850                         s8 new_node_level = -1;
1851                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
1852                         if (viscosity > 1 && liquid_levels_want[i] != liquid_levels[i]) {
1853                                 // amount to gain, limited by viscosity
1854                                 // must be at least 1 in absolute value
1855                                 s8 level_inc = liquid_levels_want[i] - liquid_levels[i];
1856                                 if (level_inc < -viscosity || level_inc > viscosity)
1857                                         new_node_level = liquid_levels[i] + level_inc/viscosity;
1858                                 else if (level_inc < 0)
1859                                         new_node_level = liquid_levels[i] - 1;
1860                                 else if (level_inc > 0)
1861                                         new_node_level = liquid_levels[i] + 1;
1862                         } else {
1863                                 new_node_level = liquid_levels_want[i];
1864                         }
1865                         
1866                         if (new_node_level >= LIQUID_LEVEL_SOURCE)
1867                                 new_node_content = liquid_kind;
1868                         else if (new_node_level > 0)
1869                                 new_node_content = liquid_kind_flowing;
1870                         else
1871                                 new_node_content = CONTENT_AIR;
1872
1873                         // last level must flow down on stairs
1874                         if (liquid_levels_want[i] != liquid_levels[i] &&
1875                                 liquid_levels[D_TOP] <= 0 && !neighbors[D_BOTTOM].l &&
1876                                 new_node_level >= 1 && new_node_level <= 2) {
1877                                 for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
1878                                         if (neighbors[ii].l)
1879                                                 must_reflow_second.push_back(p0 + dirs[ii]);
1880                                 }
1881                         }
1882
1883                         /*
1884                                 check if anything has changed.
1885                                 if not, just continue with the next node.
1886                          */
1887                         if (
1888                                  new_node_content == n0.getContent() 
1889                                 && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1890                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level 
1891                                  //&& ((n0.param2 & LIQUID_FLOW_DOWN_MASK) ==
1892                                  //LIQUID_FLOW_DOWN_MASK) == flowing_down
1893                                  ))
1894                                 &&
1895                                  (nodemgr->get(n0.getContent()).liquid_type != LIQUID_SOURCE ||
1896                                  (((n0.param2 & LIQUID_INFINITY_MASK) ==
1897                                         LIQUID_INFINITY_MASK) == neighbors[i].i
1898                                  ))
1899                            ) {
1900                                 continue;
1901                         }
1902                         ++changed;
1903
1904                         /*
1905                                 update the current node
1906                          */
1907                         if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
1908                                 // set level to last 3 bits, flowing down bit to 4th bit
1909                                 n0.param2 = (new_node_level & LIQUID_LEVEL_MASK);
1910                         } else if (nodemgr->get(new_node_content).liquid_type == LIQUID_SOURCE) {
1911                                 //n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1912                                 n0.param2 = (neighbors[i].i ? LIQUID_INFINITY_MASK : 0x00);
1913                         }
1914                         /*
1915                         infostream << "set node i=" <<(int)i<<" "<< PP(p0)<< " nc="
1916                         <<new_node_content<< " p2="<<(int)n0.param2<< " nl="
1917                         <<(int)new_node_level<<std::endl;
1918                         */
1919                         
1920                         n0.setContent(new_node_content);
1921                         // Find out whether there is a suspect for this action
1922                         std::string suspect;
1923                         if(m_gamedef->rollback()){
1924                                 suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
1925                         }
1926
1927                         if(!suspect.empty()){
1928                                 // Blame suspect
1929                                 RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
1930                                 // Get old node for rollback
1931                                 RollbackNode rollback_oldnode(this, p0, m_gamedef);
1932                                 // Set node
1933                                 setNode(p0, n0);
1934                                 // Report
1935                                 RollbackNode rollback_newnode(this, p0, m_gamedef);
1936                                 RollbackAction action;
1937                                 action.setSetNode(p0, rollback_oldnode, rollback_newnode);
1938                                 m_gamedef->rollback()->reportAction(action);
1939                         } else {
1940                                 // Set node
1941                                 setNode(p0, n0);
1942                         }
1943
1944                         v3s16 blockpos = getNodeBlockPos(p0);
1945                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1946                         if(block != NULL) {
1947                                 modified_blocks[blockpos] = block;
1948                                 // If node emits light, MapBlock requires lighting update
1949                                 if(nodemgr->get(n0).light_source != 0)
1950                                         lighting_modified_blocks[block->getPos()] = block;
1951                         }
1952                         must_reflow.push_back(neighbors[i].p);
1953                 }
1954                 /* //for better relax  only same level
1955                 if (changed)  for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) {
1956                         if (!neighbors[ii].l) continue;
1957                         must_reflow.push_back(p0 + dirs[ii]);
1958                 }*/
1959         }
1960         /*
1961         if (loopcount)
1962                 infostream<<"Map::transformLiquids(): loopcount="<<loopcount
1963                 <<" reflow="<<must_reflow.size()
1964                 <<" queue="<< m_transforming_liquid.size()<<std::endl;
1965         */
1966         while (must_reflow.size() > 0)
1967                 m_transforming_liquid.push_back(must_reflow.pop_front());
1968         while (must_reflow_second.size() > 0)
1969                 m_transforming_liquid.push_back(must_reflow_second.pop_front());
1970         updateLighting(lighting_modified_blocks, modified_blocks);
1971 }
1972
1973 void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
1974 {
1975
1976         if (g_settings->getBool("liquid_finite"))
1977                 return Map::transformLiquidsFinite(modified_blocks);
1978
1979         INodeDefManager *nodemgr = m_gamedef->ndef();
1980
1981         DSTACK(__FUNCTION_NAME);
1982         //TimeTaker timer("transformLiquids()");
1983
1984         u32 loopcount = 0;
1985         u32 initial_size = m_transforming_liquid.size();
1986
1987         /*if(initial_size != 0)
1988                 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1989
1990         // list of nodes that due to viscosity have not reached their max level height
1991         UniqueQueue<v3s16> must_reflow;
1992
1993         // List of MapBlocks that will require a lighting update (due to lava)
1994         std::map<v3s16, MapBlock*> lighting_modified_blocks;
1995
1996         while(m_transforming_liquid.size() != 0)
1997         {
1998                 // This should be done here so that it is done when continue is used
1999                 if(loopcount >= initial_size || loopcount >= 10000)
2000                         break;
2001                 loopcount++;
2002
2003                 /*
2004                         Get a queued transforming liquid node
2005                 */
2006                 v3s16 p0 = m_transforming_liquid.pop_front();
2007
2008                 MapNode n0 = getNodeNoEx(p0);
2009
2010                 /*
2011                         Collect information about current node
2012                  */
2013                 s8 liquid_level = -1;
2014                 content_t liquid_kind = CONTENT_IGNORE;
2015                 LiquidType liquid_type = nodemgr->get(n0).liquid_type;
2016                 switch (liquid_type) {
2017                         case LIQUID_SOURCE:
2018                                 liquid_level = LIQUID_LEVEL_SOURCE;
2019                                 liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing);
2020                                 break;
2021                         case LIQUID_FLOWING:
2022                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
2023                                 liquid_kind = n0.getContent();
2024                                 break;
2025                         case LIQUID_NONE:
2026                                 // if this is an air node, it *could* be transformed into a liquid. otherwise,
2027                                 // continue with the next node.
2028                                 if (n0.getContent() != CONTENT_AIR)
2029                                         continue;
2030                                 liquid_kind = CONTENT_AIR;
2031                                 break;
2032                 }
2033
2034                 /*
2035                         Collect information about the environment
2036                  */
2037                 const v3s16 *dirs = g_6dirs;
2038                 NodeNeighbor sources[6]; // surrounding sources
2039                 int num_sources = 0;
2040                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
2041                 int num_flows = 0;
2042                 NodeNeighbor airs[6]; // surrounding air
2043                 int num_airs = 0;
2044                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
2045                 int num_neutrals = 0;
2046                 bool flowing_down = false;
2047                 for (u16 i = 0; i < 6; i++) {
2048                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
2049                         switch (i) {
2050                                 case 1:
2051                                         nt = NEIGHBOR_UPPER;
2052                                         break;
2053                                 case 4:
2054                                         nt = NEIGHBOR_LOWER;
2055                                         break;
2056                         }
2057                         v3s16 npos = p0 + dirs[i];
2058                         NodeNeighbor nb = {getNodeNoEx(npos), nt, npos};
2059                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
2060                                 case LIQUID_NONE:
2061                                         if (nb.n.getContent() == CONTENT_AIR) {
2062                                                 airs[num_airs++] = nb;
2063                                                 // if the current node is a water source the neighbor
2064                                                 // should be enqueded for transformation regardless of whether the
2065                                                 // current node changes or not.
2066                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
2067                                                         m_transforming_liquid.push_back(npos);
2068                                                 // if the current node happens to be a flowing node, it will start to flow down here.
2069                                                 if (nb.t == NEIGHBOR_LOWER) {
2070                                                         flowing_down = true;
2071                                                 }
2072                                         } else {
2073                                                 neutrals[num_neutrals++] = nb;
2074                                         }
2075                                         break;
2076                                 case LIQUID_SOURCE:
2077                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
2078                                         if (liquid_kind == CONTENT_AIR)
2079                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
2080                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
2081                                                 neutrals[num_neutrals++] = nb;
2082                                         } else {
2083                                                 // Do not count bottom source, it will screw things up
2084                                                 if(dirs[i].Y != -1)
2085                                                         sources[num_sources++] = nb;
2086                                         }
2087                                         break;
2088                                 case LIQUID_FLOWING:
2089                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
2090                                         if (liquid_kind == CONTENT_AIR)
2091                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
2092                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
2093                                                 neutrals[num_neutrals++] = nb;
2094                                         } else {
2095                                                 flows[num_flows++] = nb;
2096                                                 if (nb.t == NEIGHBOR_LOWER)
2097                                                         flowing_down = true;
2098                                         }
2099                                         break;
2100                         }
2101                 }
2102
2103                 /*
2104                         decide on the type (and possibly level) of the current node
2105                  */
2106                 content_t new_node_content;
2107                 s8 new_node_level = -1;
2108                 s8 max_node_level = -1;
2109                 if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
2110                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
2111                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
2112                         // it's perfectly safe to use liquid_kind here to determine the new node content.
2113                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
2114                 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
2115                         // liquid_kind is set properly, see above
2116                         new_node_content = liquid_kind;
2117                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
2118                 } else {
2119                         // no surrounding sources, so get the maximum level that can flow into this node
2120                         for (u16 i = 0; i < num_flows; i++) {
2121                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
2122                                 switch (flows[i].t) {
2123                                         case NEIGHBOR_UPPER:
2124                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
2125                                                         max_node_level = LIQUID_LEVEL_MAX;
2126                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
2127                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
2128                                                 } else if (nb_liquid_level > max_node_level)
2129                                                         max_node_level = nb_liquid_level;
2130                                                 break;
2131                                         case NEIGHBOR_LOWER:
2132                                                 break;
2133                                         case NEIGHBOR_SAME_LEVEL:
2134                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
2135                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
2136                                                         max_node_level = nb_liquid_level - 1;
2137                                                 }
2138                                                 break;
2139                                 }
2140                         }
2141
2142                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
2143                         if (viscosity > 1 && max_node_level != liquid_level) {
2144                                 // amount to gain, limited by viscosity
2145                                 // must be at least 1 in absolute value
2146                                 s8 level_inc = max_node_level - liquid_level;
2147                                 if (level_inc < -viscosity || level_inc > viscosity)
2148                                         new_node_level = liquid_level + level_inc/viscosity;
2149                                 else if (level_inc < 0)
2150                                         new_node_level = liquid_level - 1;
2151                                 else if (level_inc > 0)
2152                                         new_node_level = liquid_level + 1;
2153                                 if (new_node_level != max_node_level)
2154                                         must_reflow.push_back(p0);
2155                         } else
2156                                 new_node_level = max_node_level;
2157
2158                         if (new_node_level >= 0)
2159                                 new_node_content = liquid_kind;
2160                         else
2161                                 new_node_content = CONTENT_AIR;
2162
2163                 }
2164
2165                 /*
2166                         check if anything has changed. if not, just continue with the next node.
2167                  */
2168                 if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
2169                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
2170                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
2171                                                                                  == flowing_down)))
2172                         continue;
2173
2174
2175                 /*
2176                         update the current node
2177                  */
2178                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
2179                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
2180                         // set level to last 3 bits, flowing down bit to 4th bit
2181                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
2182                 } else {
2183                         // set the liquid level and flow bit to 0
2184                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
2185                 }
2186                 n0.setContent(new_node_content);
2187
2188                 // Find out whether there is a suspect for this action
2189                 std::string suspect;
2190                 if(m_gamedef->rollback()){
2191                         suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
2192                 }
2193
2194                 if(!suspect.empty()){
2195                         // Blame suspect
2196                         RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
2197                         // Get old node for rollback
2198                         RollbackNode rollback_oldnode(this, p0, m_gamedef);
2199                         // Set node
2200                         setNode(p0, n0);
2201                         // Report
2202                         RollbackNode rollback_newnode(this, p0, m_gamedef);
2203                         RollbackAction action;
2204                         action.setSetNode(p0, rollback_oldnode, rollback_newnode);
2205                         m_gamedef->rollback()->reportAction(action);
2206                 } else {
2207                         // Set node
2208                         setNode(p0, n0);
2209                 }
2210
2211                 v3s16 blockpos = getNodeBlockPos(p0);
2212                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
2213                 if(block != NULL) {
2214                         modified_blocks[blockpos] =  block;
2215                         // If node emits light, MapBlock requires lighting update
2216                         if(nodemgr->get(n0).light_source != 0)
2217                                 lighting_modified_blocks[block->getPos()] = block;
2218                 }
2219
2220                 /*
2221                         enqueue neighbors for update if neccessary
2222                  */
2223                 switch (nodemgr->get(n0.getContent()).liquid_type) {
2224                         case LIQUID_SOURCE:
2225                         case LIQUID_FLOWING:
2226                                 // make sure source flows into all neighboring nodes
2227                                 for (u16 i = 0; i < num_flows; i++)
2228                                         if (flows[i].t != NEIGHBOR_UPPER)
2229                                                 m_transforming_liquid.push_back(flows[i].p);
2230                                 for (u16 i = 0; i < num_airs; i++)
2231                                         if (airs[i].t != NEIGHBOR_UPPER)
2232                                                 m_transforming_liquid.push_back(airs[i].p);
2233                                 break;
2234                         case LIQUID_NONE:
2235                                 // this flow has turned to air; neighboring flows might need to do the same
2236                                 for (u16 i = 0; i < num_flows; i++)
2237                                         m_transforming_liquid.push_back(flows[i].p);
2238                                 break;
2239                 }
2240         }
2241         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
2242         while (must_reflow.size() > 0)
2243                 m_transforming_liquid.push_back(must_reflow.pop_front());
2244         updateLighting(lighting_modified_blocks, modified_blocks);
2245 }
2246
2247 NodeMetadata* Map::getNodeMetadata(v3s16 p)
2248 {
2249         v3s16 blockpos = getNodeBlockPos(p);
2250         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2251         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2252         if(!block){
2253                 infostream<<"Map::getNodeMetadata(): Need to emerge "
2254                                 <<PP(blockpos)<<std::endl;
2255                 block = emergeBlock(blockpos, false);
2256         }
2257         if(!block)
2258         {
2259                 infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
2260                                 <<std::endl;
2261                 return NULL;
2262         }
2263         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
2264         return meta;
2265 }
2266
2267 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
2268 {
2269         v3s16 blockpos = getNodeBlockPos(p);
2270         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2271         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2272         if(!block){
2273                 infostream<<"Map::setNodeMetadata(): Need to emerge "
2274                                 <<PP(blockpos)<<std::endl;
2275                 block = emergeBlock(blockpos, false);
2276         }
2277         if(!block)
2278         {
2279                 infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
2280                                 <<std::endl;
2281                 return;
2282         }
2283         block->m_node_metadata.set(p_rel, meta);
2284 }
2285
2286 void Map::removeNodeMetadata(v3s16 p)
2287 {
2288         v3s16 blockpos = getNodeBlockPos(p);
2289         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2290         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2291         if(block == NULL)
2292         {
2293                 infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
2294                                 <<std::endl;
2295                 return;
2296         }
2297         block->m_node_metadata.remove(p_rel);
2298 }
2299
2300 NodeTimer Map::getNodeTimer(v3s16 p)
2301 {
2302         v3s16 blockpos = getNodeBlockPos(p);
2303         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2304         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2305         if(!block){
2306                 infostream<<"Map::getNodeTimer(): Need to emerge "
2307                                 <<PP(blockpos)<<std::endl;
2308                 block = emergeBlock(blockpos, false);
2309         }
2310         if(!block)
2311         {
2312                 infostream<<"WARNING: Map::getNodeTimer(): Block not found"
2313                                 <<std::endl;
2314                 return NodeTimer();
2315         }
2316         NodeTimer t = block->m_node_timers.get(p_rel);
2317         return t;
2318 }
2319
2320 void Map::setNodeTimer(v3s16 p, NodeTimer t)
2321 {
2322         v3s16 blockpos = getNodeBlockPos(p);
2323         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2324         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2325         if(!block){
2326                 infostream<<"Map::setNodeTimer(): Need to emerge "
2327                                 <<PP(blockpos)<<std::endl;
2328                 block = emergeBlock(blockpos, false);
2329         }
2330         if(!block)
2331         {
2332                 infostream<<"WARNING: Map::setNodeTimer(): Block not found"
2333                                 <<std::endl;
2334                 return;
2335         }
2336         block->m_node_timers.set(p_rel, t);
2337 }
2338
2339 void Map::removeNodeTimer(v3s16 p)
2340 {
2341         v3s16 blockpos = getNodeBlockPos(p);
2342         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2343         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2344         if(block == NULL)
2345         {
2346                 infostream<<"WARNING: Map::removeNodeTimer(): Block not found"
2347                                 <<std::endl;
2348                 return;
2349         }
2350         block->m_node_timers.remove(p_rel);
2351 }
2352
2353 /*
2354         ServerMap
2355 */
2356 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
2357         Map(dout_server, gamedef),
2358         m_seed(0),
2359         m_map_metadata_changed(true),
2360         m_database(NULL),
2361         m_database_read(NULL),
2362         m_database_write(NULL)
2363 {
2364         verbosestream<<__FUNCTION_NAME<<std::endl;
2365
2366         m_emerge = emerge;
2367         m_mgparams = m_emerge->getParamsFromSettings(g_settings);
2368         if (!m_mgparams)
2369                 m_mgparams = new MapgenV6Params();
2370
2371         m_seed = m_mgparams->seed;
2372
2373         if (g_settings->get("fixed_map_seed").empty())
2374         {
2375                 m_seed = (((u64)(myrand() & 0xffff) << 0)
2376                                 | ((u64)(myrand() & 0xffff) << 16)
2377                                 | ((u64)(myrand() & 0xffff) << 32)
2378                                 | ((u64)(myrand() & 0xffff) << 48));
2379                 m_mgparams->seed = m_seed;
2380         }
2381
2382         /*
2383                 Experimental and debug stuff
2384         */
2385
2386         {
2387         }
2388
2389         /*
2390                 Try to load map; if not found, create a new one.
2391         */
2392
2393         m_savedir = savedir;
2394         m_map_saving_enabled = false;
2395
2396         try
2397         {
2398                 // If directory exists, check contents and load if possible
2399                 if(fs::PathExists(m_savedir))
2400                 {
2401                         // If directory is empty, it is safe to save into it.
2402                         if(fs::GetDirListing(m_savedir).size() == 0)
2403                         {
2404                                 infostream<<"ServerMap: Empty save directory is valid."
2405                                                 <<std::endl;
2406                                 m_map_saving_enabled = true;
2407                         }
2408                         else
2409                         {
2410                                 try{
2411                                         // Load map metadata (seed, chunksize)
2412                                         loadMapMeta();
2413                                 }
2414                                 catch(SettingNotFoundException &e){
2415                                         infostream<<"ServerMap:  Some metadata not found."
2416                                                           <<" Using default settings."<<std::endl;
2417                                 }
2418                                 catch(FileNotGoodException &e){
2419                                         infostream<<"WARNING: Could not load map metadata"
2420                                                         //<<" Disabling chunk-based generator."
2421                                                         <<std::endl;
2422                                         //m_chunksize = 0;
2423                                 }
2424
2425                                 infostream<<"ServerMap: Successfully loaded map "
2426                                                 <<"metadata from "<<savedir
2427                                                 <<", assuming valid save directory."
2428                                                 <<" seed="<<m_seed<<"."
2429                                                 <<std::endl;
2430
2431                                 m_map_saving_enabled = true;
2432                                 // Map loaded, not creating new one
2433                                 return;
2434                         }
2435                 }
2436                 // If directory doesn't exist, it is safe to save to it
2437                 else{
2438                         m_map_saving_enabled = true;
2439                 }
2440         }
2441         catch(std::exception &e)
2442         {
2443                 infostream<<"WARNING: ServerMap: Failed to load map from "<<savedir
2444                                 <<", exception: "<<e.what()<<std::endl;
2445                 infostream<<"Please remove the map or fix it."<<std::endl;
2446                 infostream<<"WARNING: Map saving will be disabled."<<std::endl;
2447         }
2448
2449         infostream<<"Initializing new map."<<std::endl;
2450
2451         // Create zero sector
2452         emergeSector(v2s16(0,0));
2453
2454         // Initially write whole map
2455         save(MOD_STATE_CLEAN);
2456 }
2457
2458 ServerMap::~ServerMap()
2459 {
2460         verbosestream<<__FUNCTION_NAME<<std::endl;
2461
2462         try
2463         {
2464                 if(m_map_saving_enabled)
2465                 {
2466                         // Save only changed parts
2467                         save(MOD_STATE_WRITE_AT_UNLOAD);
2468                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
2469                 }
2470                 else
2471                 {
2472                         infostream<<"ServerMap: Map not saved"<<std::endl;
2473                 }
2474         }
2475         catch(std::exception &e)
2476         {
2477                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
2478                                 <<", exception: "<<e.what()<<std::endl;
2479         }
2480
2481         /*
2482                 Close database if it was opened
2483         */
2484         if(m_database_read)
2485                 sqlite3_finalize(m_database_read);
2486         if(m_database_write)
2487                 sqlite3_finalize(m_database_write);
2488         if(m_database)
2489                 sqlite3_close(m_database);
2490
2491 #if 0
2492         /*
2493                 Free all MapChunks
2494         */
2495         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2496         for(; i.atEnd() == false; i++)
2497         {
2498                 MapChunk *chunk = i.getNode()->getValue();
2499                 delete chunk;
2500         }
2501 #endif
2502
2503         delete m_mgparams;
2504 }
2505
2506 bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
2507 {
2508         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2509         EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
2510
2511         s16 chunksize = m_mgparams->chunksize;
2512         s16 coffset = -chunksize / 2;
2513         v3s16 chunk_offset(coffset, coffset, coffset);
2514         v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
2515         v3s16 blockpos_min = blockpos_div * chunksize;
2516         v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
2517         blockpos_min += chunk_offset;
2518         blockpos_max += chunk_offset;
2519
2520         v3s16 extra_borders(1,1,1);
2521
2522         // Do nothing if not inside limits (+-1 because of neighbors)
2523         if(blockpos_over_limit(blockpos_min - extra_borders) ||
2524                 blockpos_over_limit(blockpos_max + extra_borders))
2525                 return false;
2526
2527         data->seed = m_seed;
2528         data->blockpos_min = blockpos_min;
2529         data->blockpos_max = blockpos_max;
2530         data->blockpos_requested = blockpos;
2531         data->nodedef = m_gamedef->ndef();
2532
2533         /*
2534                 Create the whole area of this and the neighboring blocks
2535         */
2536         {
2537                 //TimeTaker timer("initBlockMake() create area");
2538
2539                 for(s16 x=blockpos_min.X-extra_borders.X;
2540                                 x<=blockpos_max.X+extra_borders.X; x++)
2541                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2542                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2543                 {
2544                         v2s16 sectorpos(x, z);
2545                         // Sector metadata is loaded from disk if not already loaded.
2546                         ServerMapSector *sector = createSector(sectorpos);
2547                         assert(sector);
2548
2549                         for(s16 y=blockpos_min.Y-extra_borders.Y;
2550                                         y<=blockpos_max.Y+extra_borders.Y; y++)
2551                         {
2552                                 v3s16 p(x,y,z);
2553                                 //MapBlock *block = createBlock(p);
2554                                 // 1) get from memory, 2) load from disk
2555                                 MapBlock *block = emergeBlock(p, false);
2556                                 // 3) create a blank one
2557                                 if(block == NULL)
2558                                 {
2559                                         block = createBlock(p);
2560
2561                                         /*
2562                                                 Block gets sunlight if this is true.
2563
2564                                                 Refer to the map generator heuristics.
2565                                         */
2566                                         bool ug = m_emerge->isBlockUnderground(p);
2567                                         block->setIsUnderground(ug);
2568                                 }
2569
2570                                 // Lighting will not be valid after make_chunk is called
2571                                 block->setLightingExpired(true);
2572                                 // Lighting will be calculated
2573                                 //block->setLightingExpired(false);
2574                         }
2575                 }
2576         }
2577
2578         /*
2579                 Now we have a big empty area.
2580
2581                 Make a ManualMapVoxelManipulator that contains this and the
2582                 neighboring blocks
2583         */
2584
2585         // The area that contains this block and it's neighbors
2586         v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
2587         v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
2588
2589         data->vmanip = new ManualMapVoxelManipulator(this);
2590         //data->vmanip->setMap(this);
2591
2592         // Add the area
2593         {
2594                 //TimeTaker timer("initBlockMake() initialEmerge");
2595                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2596         }
2597         
2598         // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE
2599 /*      for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
2600                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
2601                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
2602                                 core::map<v3s16, u8>::Node *n;
2603                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
2604                                 if (n == NULL)
2605                                         continue;
2606                                 u8 flags = n->getValue();
2607                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
2608                                 n->setValue(flags);
2609                         }
2610                 }
2611         }*/
2612
2613         // Data is ready now.
2614         return true;
2615 }
2616
2617 MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
2618                 std::map<v3s16, MapBlock*> &changed_blocks)
2619 {
2620         v3s16 blockpos_min = data->blockpos_min;
2621         v3s16 blockpos_max = data->blockpos_max;
2622         v3s16 blockpos_requested = data->blockpos_requested;
2623         /*infostream<<"finishBlockMake(): ("<<blockpos_requested.X<<","
2624                         <<blockpos_requested.Y<<","
2625                         <<blockpos_requested.Z<<")"<<std::endl;*/
2626
2627         v3s16 extra_borders(1,1,1);
2628
2629         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2630
2631         /*infostream<<"Resulting vmanip:"<<std::endl;
2632         data->vmanip.print(infostream);*/
2633
2634         // Make sure affected blocks are loaded
2635         for(s16 x=blockpos_min.X-extra_borders.X;
2636                         x<=blockpos_max.X+extra_borders.X; x++)
2637         for(s16 z=blockpos_min.Z-extra_borders.Z;
2638                         z<=blockpos_max.Z+extra_borders.Z; z++)
2639         for(s16 y=blockpos_min.Y-extra_borders.Y;
2640                         y<=blockpos_max.Y+extra_borders.Y; y++)
2641         {
2642                 v3s16 p(x, y, z);
2643                 // Load from disk if not already in memory
2644                 emergeBlock(p, false);
2645         }
2646
2647         /*
2648                 Blit generated stuff to map
2649                 NOTE: blitBackAll adds nearly everything to changed_blocks
2650         */
2651         {
2652                 // 70ms @cs=8
2653                 //TimeTaker timer("finishBlockMake() blitBackAll");
2654                 data->vmanip->blitBackAll(&changed_blocks);
2655         }
2656
2657         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
2658
2659         /*
2660                 Copy transforming liquid information
2661         */
2662         while(data->transforming_liquid.size() > 0)
2663         {
2664                 v3s16 p = data->transforming_liquid.pop_front();
2665                 m_transforming_liquid.push_back(p);
2666         }
2667
2668         /*
2669                 Do stuff in central blocks
2670         */
2671
2672         /*
2673                 Update lighting
2674         */
2675         {
2676 #if 0
2677                 TimeTaker t("finishBlockMake lighting update");
2678
2679                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2680
2681                 // Center blocks
2682                 for(s16 x=blockpos_min.X-extra_borders.X;
2683                                 x<=blockpos_max.X+extra_borders.X; x++)
2684                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2685                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2686                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2687                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2688                 {
2689                         v3s16 p(x, y, z);
2690                         MapBlock *block = getBlockNoCreateNoEx(p);
2691                         assert(block);
2692                         lighting_update_blocks.insert(block->getPos(), block);
2693                 }
2694
2695                 updateLighting(lighting_update_blocks, changed_blocks);
2696 #endif
2697
2698                 /*
2699                         Set lighting to non-expired state in all of them.
2700                         This is cheating, but it is not fast enough if all of them
2701                         would actually be updated.
2702                 */
2703                 for(s16 x=blockpos_min.X-extra_borders.X;
2704                                 x<=blockpos_max.X+extra_borders.X; x++)
2705                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2706                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2707                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2708                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2709                 {
2710                         v3s16 p(x, y, z);
2711                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2712                 }
2713
2714 #if 0
2715                 if(enable_mapgen_debug_info == false)
2716                         t.stop(true); // Hide output
2717 #endif
2718         }
2719
2720         /*
2721                 Go through changed blocks
2722         */
2723         for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
2724                         i != changed_blocks.end(); ++i)
2725         {
2726                 MapBlock *block = i->second;
2727                 assert(block);
2728                 /*
2729                         Update day/night difference cache of the MapBlocks
2730                 */
2731                 block->expireDayNightDiff();
2732                 /*
2733                         Set block as modified
2734                 */
2735                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2736                                 "finishBlockMake expireDayNightDiff");
2737         }
2738
2739         /*
2740                 Set central blocks as generated
2741         */
2742         for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)
2743         for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)
2744         for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++)
2745         {
2746                 v3s16 p(x, y, z);
2747                 MapBlock *block = getBlockNoCreateNoEx(p);
2748                 assert(block);
2749                 block->setGenerated(true);
2750         }
2751
2752         /*
2753                 Save changed parts of map
2754                 NOTE: Will be saved later.
2755         */
2756         //save(MOD_STATE_WRITE_AT_UNLOAD);
2757
2758         /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
2759                         <<","<<blockpos_requested.Y<<","
2760                         <<blockpos_requested.Z<<")"<<std::endl;*/
2761 #if 0
2762         if(enable_mapgen_debug_info)
2763         {
2764                 /*
2765                         Analyze resulting blocks
2766                 */
2767                 /*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
2768                 for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
2769                 for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
2770                 for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
2771                 for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
2772                 for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
2773                 {
2774                         v3s16 p = v3s16(x,y,z);
2775                         MapBlock *block = getBlockNoCreateNoEx(p);
2776                         char spos[20];
2777                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2778                         infostream<<"Generated "<<spos<<": "
2779                                         <<analyze_block(block)<<std::endl;
2780                 }
2781         }
2782 #endif
2783
2784         MapBlock *block = getBlockNoCreateNoEx(blockpos_requested);
2785         assert(block);
2786
2787         return block;
2788 }
2789
2790 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2791 {
2792         DSTACKF("%s: p2d=(%d,%d)",
2793                         __FUNCTION_NAME,
2794                         p2d.X, p2d.Y);
2795
2796         /*
2797                 Check if it exists already in memory
2798         */
2799         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2800         if(sector != NULL)
2801                 return sector;
2802
2803         /*
2804                 Try to load it from disk (with blocks)
2805         */
2806         //if(loadSectorFull(p2d) == true)
2807
2808         /*
2809                 Try to load metadata from disk
2810         */
2811 #if 0
2812         if(loadSectorMeta(p2d) == true)
2813         {
2814                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2815                 if(sector == NULL)
2816                 {
2817                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2818                         throw InvalidPositionException("");
2819                 }
2820                 return sector;
2821         }
2822 #endif
2823         /*
2824                 Do not create over-limit
2825         */
2826         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2827         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2828         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2829         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2830                 throw InvalidPositionException("createSector(): pos. over limit");
2831
2832         /*
2833                 Generate blank sector
2834         */
2835
2836         sector = new ServerMapSector(this, p2d, m_gamedef);
2837
2838         // Sector position on map in nodes
2839         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2840
2841         /*
2842                 Insert to container
2843         */
2844         m_sectors[p2d] = sector;
2845
2846         return sector;
2847 }
2848
2849 #if 0
2850 /*
2851         This is a quick-hand function for calling makeBlock().
2852 */
2853 MapBlock * ServerMap::generateBlock(
2854                 v3s16 p,
2855                 std::map<v3s16, MapBlock*> &modified_blocks
2856 )
2857 {
2858         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2859
2860         /*infostream<<"generateBlock(): "
2861                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2862                         <<std::endl;*/
2863
2864         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2865
2866         TimeTaker timer("generateBlock");
2867
2868         //MapBlock *block = original_dummy;
2869
2870         v2s16 p2d(p.X, p.Z);
2871         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2872
2873         /*
2874                 Do not generate over-limit
2875         */
2876         if(blockpos_over_limit(p))
2877         {
2878                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2879                 throw InvalidPositionException("generateBlock(): pos. over limit");
2880         }
2881
2882         /*
2883                 Create block make data
2884         */
2885         BlockMakeData data;
2886         initBlockMake(&data, p);
2887
2888         /*
2889                 Generate block
2890         */
2891         {
2892                 TimeTaker t("mapgen::make_block()");
2893                 mapgen->makeChunk(&data);
2894                 //mapgen::make_block(&data);
2895
2896                 if(enable_mapgen_debug_info == false)
2897                         t.stop(true); // Hide output
2898         }
2899
2900         /*
2901                 Blit data back on map, update lighting, add mobs and whatever this does
2902         */
2903         finishBlockMake(&data, modified_blocks);
2904
2905         /*
2906                 Get central block
2907         */
2908         MapBlock *block = getBlockNoCreateNoEx(p);
2909
2910 #if 0
2911         /*
2912                 Check result
2913         */
2914         if(block)
2915         {
2916                 bool erroneus_content = false;
2917                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2918                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2919                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2920                 {
2921                         v3s16 p(x0,y0,z0);
2922                         MapNode n = block->getNode(p);
2923                         if(n.getContent() == CONTENT_IGNORE)
2924                         {
2925                                 infostream<<"CONTENT_IGNORE at "
2926                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2927                                                 <<std::endl;
2928                                 erroneus_content = true;
2929                                 assert(0);
2930                         }
2931                 }
2932                 if(erroneus_content)
2933                 {
2934                         assert(0);
2935                 }
2936         }
2937 #endif
2938
2939 #if 0
2940         /*
2941                 Generate a completely empty block
2942         */
2943         if(block)
2944         {
2945                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2946                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2947                 {
2948                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2949                         {
2950                                 MapNode n;
2951                                 n.setContent(CONTENT_AIR);
2952                                 block->setNode(v3s16(x0,y0,z0), n);
2953                         }
2954                 }
2955         }
2956 #endif
2957
2958         if(enable_mapgen_debug_info == false)
2959                 timer.stop(true); // Hide output
2960
2961         return block;
2962 }
2963 #endif
2964
2965 MapBlock * ServerMap::createBlock(v3s16 p)
2966 {
2967         DSTACKF("%s: p=(%d,%d,%d)",
2968                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2969
2970         /*
2971                 Do not create over-limit
2972         */
2973         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2974         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2975         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2976         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2977         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2978         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2979                 throw InvalidPositionException("createBlock(): pos. over limit");
2980
2981         v2s16 p2d(p.X, p.Z);
2982         s16 block_y = p.Y;
2983         /*
2984                 This will create or load a sector if not found in memory.
2985                 If block exists on disk, it will be loaded.
2986
2987                 NOTE: On old save formats, this will be slow, as it generates
2988                       lighting on blocks for them.
2989         */
2990         ServerMapSector *sector;
2991         try{
2992                 sector = (ServerMapSector*)createSector(p2d);
2993                 assert(sector->getId() == MAPSECTOR_SERVER);
2994         }
2995         catch(InvalidPositionException &e)
2996         {
2997                 infostream<<"createBlock: createSector() failed"<<std::endl;
2998                 throw e;
2999         }
3000         /*
3001                 NOTE: This should not be done, or at least the exception
3002                 should not be passed on as std::exception, because it
3003                 won't be catched at all.
3004         */
3005         /*catch(std::exception &e)
3006         {
3007                 infostream<<"createBlock: createSector() failed: "
3008                                 <<e.what()<<std::endl;
3009                 throw e;
3010         }*/
3011
3012         /*
3013                 Try to get a block from the sector
3014         */
3015
3016         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
3017         if(block)
3018         {
3019                 if(block->isDummy())
3020                         block->unDummify();
3021                 return block;
3022         }
3023         // Create blank
3024         block = sector->createBlankBlock(block_y);
3025
3026         return block;
3027 }
3028
3029 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
3030 {
3031         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
3032                         __FUNCTION_NAME,
3033                         p.X, p.Y, p.Z, create_blank);
3034
3035         {
3036                 MapBlock *block = getBlockNoCreateNoEx(p);
3037                 if(block && block->isDummy() == false)
3038                         return block;
3039         }
3040
3041         {
3042                 MapBlock *block = loadBlock(p);
3043                 if(block)
3044                         return block;
3045         }
3046
3047         if (create_blank) {
3048                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
3049                 MapBlock *block = sector->createBlankBlock(p.Y);
3050
3051                 return block;
3052         }
3053         /*if(allow_generate)
3054         {
3055                 std::map<v3s16, MapBlock*> modified_blocks;
3056                 MapBlock *block = generateBlock(p, modified_blocks);
3057                 if(block)
3058                 {
3059                         MapEditEvent event;
3060                         event.type = MEET_OTHER;
3061                         event.p = p;
3062
3063                         // Copy modified_blocks to event
3064                         for(std::map<v3s16, MapBlock*>::iterator
3065                                         i = modified_blocks.begin();
3066                                         i != modified_blocks.end(); ++i)
3067                         {
3068                                 event.modified_blocks.insert(i->first);
3069                         }
3070
3071                         // Queue event
3072                         dispatchEvent(&event);
3073
3074                         return block;
3075                 }
3076         }*/
3077
3078         return NULL;
3079 }
3080
3081 s16 ServerMap::findGroundLevel(v2s16 p2d)
3082 {
3083 #if 0
3084         /*
3085                 Uh, just do something random...
3086         */
3087         // Find existing map from top to down
3088         s16 max=63;
3089         s16 min=-64;
3090         v3s16 p(p2d.X, max, p2d.Y);
3091         for(; p.Y>min; p.Y--)
3092         {
3093                 MapNode n = getNodeNoEx(p);
3094                 if(n.getContent() != CONTENT_IGNORE)
3095                         break;
3096         }
3097         if(p.Y == min)
3098                 goto plan_b;
3099         // If this node is not air, go to plan b
3100         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
3101                 goto plan_b;
3102         // Search existing walkable and return it
3103         for(; p.Y>min; p.Y--)
3104         {
3105                 MapNode n = getNodeNoEx(p);
3106                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
3107                         return p.Y;
3108         }
3109
3110         // Move to plan b
3111 plan_b:
3112 #endif
3113
3114         /*
3115                 Determine from map generator noise functions
3116         */
3117
3118         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
3119         return level;
3120
3121         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
3122         //return (s16)level;
3123 }
3124
3125 void ServerMap::createDatabase() {
3126         int e;
3127         assert(m_database);
3128         e = sqlite3_exec(m_database,
3129                 "CREATE TABLE IF NOT EXISTS `blocks` ("
3130                         "`pos` INT NOT NULL PRIMARY KEY,"
3131                         "`data` BLOB"
3132                 ");"
3133         , NULL, NULL, NULL);
3134         if(e == SQLITE_ABORT)
3135                 throw FileNotGoodException("Could not create database structure");
3136         else
3137                 infostream<<"ServerMap: Database structure was created";
3138 }
3139
3140 void ServerMap::verifyDatabase() {
3141         if(m_database)
3142                 return;
3143
3144         {
3145                 std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
3146                 bool needs_create = false;
3147                 int d;
3148
3149                 /*
3150                         Open the database connection
3151                 */
3152
3153                 createDirs(m_savedir);
3154
3155                 if(!fs::PathExists(dbp))
3156                         needs_create = true;
3157
3158                 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
3159                 if(d != SQLITE_OK) {
3160                         infostream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
3161                         throw FileNotGoodException("Cannot open database file");
3162                 }
3163
3164                 if(needs_create)
3165                         createDatabase();
3166
3167                 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
3168                 if(d != SQLITE_OK) {
3169                         infostream<<"WARNING: Database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
3170                         throw FileNotGoodException("Cannot prepare read statement");
3171                 }
3172
3173                 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
3174                 if(d != SQLITE_OK) {
3175                         infostream<<"WARNING: Database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
3176                         throw FileNotGoodException("Cannot prepare write statement");
3177                 }
3178
3179                 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
3180                 if(d != SQLITE_OK) {
3181                         infostream<<"WARNING: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
3182                         throw FileNotGoodException("Cannot prepare read statement");
3183                 }
3184
3185                 infostream<<"ServerMap: Database opened"<<std::endl;
3186         }
3187 }
3188
3189 bool ServerMap::loadFromFolders() {
3190         if(!m_database && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
3191                 return true;
3192         return false;
3193 }
3194
3195 sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
3196         return (sqlite3_int64)pos.Z*16777216 +
3197                 (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
3198 }
3199
3200 void ServerMap::createDirs(std::string path)
3201 {
3202         if(fs::CreateAllDirs(path) == false)
3203         {
3204                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
3205                                 <<"\""<<path<<"\""<<std::endl;
3206                 throw BaseException("ServerMap failed to create directory");
3207         }
3208 }
3209
3210 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
3211 {
3212         char cc[9];
3213         switch(layout)
3214         {
3215                 case 1:
3216                         snprintf(cc, 9, "%.4x%.4x",
3217                                 (unsigned int)pos.X&0xffff,
3218                                 (unsigned int)pos.Y&0xffff);
3219
3220                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
3221                 case 2:
3222                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
3223                                 (unsigned int)pos.X&0xfff,
3224                                 (unsigned int)pos.Y&0xfff);
3225
3226                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
3227                 default:
3228                         assert(false);
3229         }
3230 }
3231
3232 v2s16 ServerMap::getSectorPos(std::string dirname)
3233 {
3234         unsigned int x, y;
3235         int r;
3236         size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
3237         assert(spos != std::string::npos);
3238         if(dirname.size() - spos == 8)
3239         {
3240                 // Old layout
3241                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
3242         }
3243         else if(dirname.size() - spos == 3)
3244         {
3245                 // New layout
3246                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
3247                 // Sign-extend the 12 bit values up to 16 bits...
3248                 if(x&0x800) x|=0xF000;
3249                 if(y&0x800) y|=0xF000;
3250         }
3251         else
3252         {
3253                 assert(false);
3254         }
3255         assert(r == 2);
3256         v2s16 pos((s16)x, (s16)y);
3257         return pos;
3258 }
3259
3260 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
3261 {
3262         v2s16 p2d = getSectorPos(sectordir);
3263
3264         if(blockfile.size() != 4){
3265                 throw InvalidFilenameException("Invalid block filename");
3266         }
3267         unsigned int y;
3268         int r = sscanf(blockfile.c_str(), "%4x", &y);
3269         if(r != 1)
3270                 throw InvalidFilenameException("Invalid block filename");
3271         return v3s16(p2d.X, y, p2d.Y);
3272 }
3273
3274 std::string ServerMap::getBlockFilename(v3s16 p)
3275 {
3276         char cc[5];
3277         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
3278         return cc;
3279 }
3280
3281 void ServerMap::save(ModifiedState save_level)
3282 {
3283         DSTACK(__FUNCTION_NAME);
3284         if(m_map_saving_enabled == false)
3285         {
3286                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
3287                 return;
3288         }
3289
3290         if(save_level == MOD_STATE_CLEAN)
3291                 infostream<<"ServerMap: Saving whole map, this can take time."
3292                                 <<std::endl;
3293
3294         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
3295         {
3296                 saveMapMeta();
3297         }
3298
3299         // Profile modified reasons
3300         Profiler modprofiler;
3301
3302         u32 sector_meta_count = 0;
3303         u32 block_count = 0;
3304         u32 block_count_all = 0; // Number of blocks in memory
3305
3306         // Don't do anything with sqlite unless something is really saved
3307         bool save_started = false;
3308
3309         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
3310                 i != m_sectors.end(); ++i)
3311         {
3312                 ServerMapSector *sector = (ServerMapSector*)i->second;
3313                 assert(sector->getId() == MAPSECTOR_SERVER);
3314
3315                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
3316                 {
3317                         saveSectorMeta(sector);
3318                         sector_meta_count++;
3319                 }
3320                 std::list<MapBlock*> blocks;
3321                 sector->getBlocks(blocks);
3322
3323                 for(std::list<MapBlock*>::iterator j = blocks.begin();
3324                         j != blocks.end(); ++j)
3325                 {
3326                         MapBlock *block = *j;
3327
3328                         block_count_all++;
3329
3330                         if(block->getModified() >= (u32)save_level)
3331                         {
3332                                 // Lazy beginSave()
3333                                 if(!save_started){
3334                                         beginSave();
3335                                         save_started = true;
3336                                 }
3337
3338                                 modprofiler.add(block->getModifiedReason(), 1);
3339
3340                                 saveBlock(block);
3341                                 block_count++;
3342
3343                                 /*infostream<<"ServerMap: Written block ("
3344                                                 <<block->getPos().X<<","
3345                                                 <<block->getPos().Y<<","
3346                                                 <<block->getPos().Z<<")"
3347                                                 <<std::endl;*/
3348                         }
3349                 }
3350         }
3351         if(save_started)
3352                 endSave();
3353
3354         /*
3355                 Only print if something happened or saved whole map
3356         */
3357         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
3358                         || block_count != 0)
3359         {
3360                 infostream<<"ServerMap: Written: "
3361                                 <<sector_meta_count<<" sector metadata files, "
3362                                 <<block_count<<" block files"
3363                                 <<", "<<block_count_all<<" blocks in memory."
3364                                 <<std::endl;
3365                 PrintInfo(infostream); // ServerMap/ClientMap:
3366                 infostream<<"Blocks modified by: "<<std::endl;
3367                 modprofiler.print(infostream);
3368         }
3369 }
3370
3371 static s32 unsignedToSigned(s32 i, s32 max_positive)
3372 {
3373         if(i < max_positive)
3374                 return i;
3375         else
3376                 return i - 2*max_positive;
3377 }
3378
3379 // modulo of a negative number does not work consistently in C
3380 static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod)
3381 {
3382         if(i >= 0)
3383                 return i % mod;
3384         return mod - ((-i) % mod);
3385 }
3386
3387 v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
3388 {
3389         s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3390         i = (i - x) / 4096;
3391         s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3392         i = (i - y) / 4096;
3393         s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3394         return v3s16(x,y,z);
3395 }
3396
3397 void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst)
3398 {
3399         if(loadFromFolders()){
3400                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
3401                                 <<"all blocks that are stored in flat files"<<std::endl;
3402         }
3403
3404         {
3405                 verifyDatabase();
3406
3407                 while(sqlite3_step(m_database_list) == SQLITE_ROW)
3408                 {
3409                         sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
3410                         v3s16 p = getIntegerAsBlock(block_i);
3411                         //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
3412                         dst.push_back(p);
3413                 }
3414         }
3415 }
3416
3417 void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst)
3418 {
3419         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
3420                 si != m_sectors.end(); ++si)
3421         {
3422                 MapSector *sector = si->second;
3423
3424                 std::list<MapBlock*> blocks;
3425                 sector->getBlocks(blocks);
3426
3427                 for(std::list<MapBlock*>::iterator i = blocks.begin();
3428                                 i != blocks.end(); ++i)
3429                 {
3430                         MapBlock *block = (*i);
3431                         v3s16 p = block->getPos();
3432                         dst.push_back(p);
3433                 }
3434         }
3435 }
3436
3437 void ServerMap::saveMapMeta()
3438 {
3439         DSTACK(__FUNCTION_NAME);
3440
3441         /*infostream<<"ServerMap::saveMapMeta(): "
3442                         <<"seed="<<m_seed
3443                         <<std::endl;*/
3444
3445         createDirs(m_savedir);
3446
3447         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3448         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
3449         if(os.good() == false)
3450         {
3451                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
3452                                 <<"could not open"<<fullpath<<std::endl;
3453                 throw FileNotGoodException("Cannot open chunk metadata");
3454         }
3455
3456         Settings params;
3457
3458         m_emerge->setParamsToSettings(&params);
3459         params.writeLines(os);
3460
3461         os<<"[end_of_params]\n";
3462
3463         m_map_metadata_changed = false;
3464 }
3465
3466 void ServerMap::loadMapMeta()
3467 {
3468         DSTACK(__FUNCTION_NAME);
3469
3470         /*infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
3471                         <<std::endl;*/
3472
3473         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3474         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3475         if(is.good() == false)
3476         {
3477                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
3478                                 <<"could not open"<<fullpath<<std::endl;
3479                 throw FileNotGoodException("Cannot open map metadata");
3480         }
3481
3482         Settings params;
3483
3484         for(;;)
3485         {
3486                 if(is.eof())
3487                         throw SerializationError
3488                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3489                 std::string line;
3490                 std::getline(is, line);
3491                 std::string trimmedline = trim(line);
3492                 if(trimmedline == "[end_of_params]")
3493                         break;
3494                 params.parseConfigLine(line);
3495         }
3496         
3497         MapgenParams *mgparams;
3498         try {
3499                 mgparams = m_emerge->getParamsFromSettings(&params);
3500         } catch (SettingNotFoundException &e) {
3501                 infostream << "Couldn't get a setting from map_meta.txt: "
3502                                    << e.what() << std::endl;
3503                 mgparams = NULL;
3504         }
3505         
3506         if (mgparams) {
3507                 if (m_mgparams)
3508                         delete m_mgparams;
3509                 m_mgparams = mgparams;
3510                 m_seed = mgparams->seed;
3511         } else {
3512                 if (params.exists("seed")) {
3513                         m_seed = params.getU64("seed");
3514                         m_mgparams->seed = m_seed;
3515                 }
3516         }
3517
3518         verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
3519 }
3520
3521 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3522 {
3523         DSTACK(__FUNCTION_NAME);
3524         // Format used for writing
3525         u8 version = SER_FMT_VER_HIGHEST;
3526         // Get destination
3527         v2s16 pos = sector->getPos();
3528         std::string dir = getSectorDir(pos);
3529         createDirs(dir);
3530
3531         std::string fullpath = dir + DIR_DELIM + "meta";
3532         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3533         if(o.good() == false)
3534                 throw FileNotGoodException("Cannot open sector metafile");
3535
3536         sector->serialize(o, version);
3537
3538         sector->differs_from_disk = false;
3539 }
3540
3541 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3542 {
3543         DSTACK(__FUNCTION_NAME);
3544         // Get destination
3545         v2s16 p2d = getSectorPos(sectordir);
3546
3547         ServerMapSector *sector = NULL;
3548
3549         std::string fullpath = sectordir + DIR_DELIM + "meta";
3550         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3551         if(is.good() == false)
3552         {
3553                 // If the directory exists anyway, it probably is in some old
3554                 // format. Just go ahead and create the sector.
3555                 if(fs::PathExists(sectordir))
3556                 {
3557                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3558                                         <<fullpath<<" doesn't exist but directory does."
3559                                         <<" Continuing with a sector with no metadata."
3560                                         <<std::endl;*/
3561                         sector = new ServerMapSector(this, p2d, m_gamedef);
3562                         m_sectors[p2d] = sector;
3563                 }
3564                 else
3565                 {
3566                         throw FileNotGoodException("Cannot open sector metafile");
3567                 }
3568         }
3569         else
3570         {
3571                 sector = ServerMapSector::deSerialize
3572                                 (is, this, p2d, m_sectors, m_gamedef);
3573                 if(save_after_load)
3574                         saveSectorMeta(sector);
3575         }
3576
3577         sector->differs_from_disk = false;
3578
3579         return sector;
3580 }
3581
3582 bool ServerMap::loadSectorMeta(v2s16 p2d)
3583 {
3584         DSTACK(__FUNCTION_NAME);
3585
3586         MapSector *sector = NULL;
3587
3588         // The directory layout we're going to load from.
3589         //  1 - original sectors/xxxxzzzz/
3590         //  2 - new sectors2/xxx/zzz/
3591         //  If we load from anything but the latest structure, we will
3592         //  immediately save to the new one, and remove the old.
3593         int loadlayout = 1;
3594         std::string sectordir1 = getSectorDir(p2d, 1);
3595         std::string sectordir;
3596         if(fs::PathExists(sectordir1))
3597         {
3598                 sectordir = sectordir1;
3599         }
3600         else
3601         {
3602                 loadlayout = 2;
3603                 sectordir = getSectorDir(p2d, 2);
3604         }
3605
3606         try{
3607                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3608         }
3609         catch(InvalidFilenameException &e)
3610         {
3611                 return false;
3612         }
3613         catch(FileNotGoodException &e)
3614         {
3615                 return false;
3616         }
3617         catch(std::exception &e)
3618         {
3619                 return false;
3620         }
3621
3622         return true;
3623 }
3624
3625 #if 0
3626 bool ServerMap::loadSectorFull(v2s16 p2d)
3627 {
3628         DSTACK(__FUNCTION_NAME);
3629
3630         MapSector *sector = NULL;
3631
3632         // The directory layout we're going to load from.
3633         //  1 - original sectors/xxxxzzzz/
3634         //  2 - new sectors2/xxx/zzz/
3635         //  If we load from anything but the latest structure, we will
3636         //  immediately save to the new one, and remove the old.
3637         int loadlayout = 1;
3638         std::string sectordir1 = getSectorDir(p2d, 1);
3639         std::string sectordir;
3640         if(fs::PathExists(sectordir1))
3641         {
3642                 sectordir = sectordir1;
3643         }
3644         else
3645         {
3646                 loadlayout = 2;
3647                 sectordir = getSectorDir(p2d, 2);
3648         }
3649
3650         try{
3651                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3652         }
3653         catch(InvalidFilenameException &e)
3654         {
3655                 return false;
3656         }
3657         catch(FileNotGoodException &e)
3658         {
3659                 return false;
3660         }
3661         catch(std::exception &e)
3662         {
3663                 return false;
3664         }
3665
3666         /*
3667                 Load blocks
3668         */
3669         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3670                         (sectordir);
3671         std::vector<fs::DirListNode>::iterator i2;
3672         for(i2=list2.begin(); i2!=list2.end(); i2++)
3673         {
3674                 // We want files
3675                 if(i2->dir)
3676                         continue;
3677                 try{
3678                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3679                 }
3680                 catch(InvalidFilenameException &e)
3681                 {
3682                         // This catches unknown crap in directory
3683                 }
3684         }
3685
3686         if(loadlayout != 2)
3687         {
3688                 infostream<<"Sector converted to new layout - deleting "<<
3689                         sectordir1<<std::endl;
3690                 fs::RecursiveDelete(sectordir1);
3691         }
3692
3693         return true;
3694 }
3695 #endif
3696
3697 void ServerMap::beginSave() {
3698         verifyDatabase();
3699         if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
3700                 infostream<<"WARNING: beginSave() failed, saving might be slow.";
3701 }
3702
3703 void ServerMap::endSave() {
3704         verifyDatabase();
3705         if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
3706                 infostream<<"WARNING: endSave() failed, map might not have saved.";
3707 }
3708
3709 void ServerMap::saveBlock(MapBlock *block)
3710 {
3711         DSTACK(__FUNCTION_NAME);
3712         /*
3713                 Dummy blocks are not written
3714         */
3715         if(block->isDummy())
3716         {
3717                 /*v3s16 p = block->getPos();
3718                 infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3719                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3720                 return;
3721         }
3722
3723         // Format used for writing
3724         u8 version = SER_FMT_VER_HIGHEST;
3725         // Get destination
3726         v3s16 p3d = block->getPos();
3727
3728
3729 #if 0
3730         v2s16 p2d(p3d.X, p3d.Z);
3731         std::string sectordir = getSectorDir(p2d);
3732
3733         createDirs(sectordir);
3734
3735         std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
3736         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3737         if(o.good() == false)
3738                 throw FileNotGoodException("Cannot open block data");
3739 #endif
3740         /*
3741                 [0] u8 serialization version
3742                 [1] data
3743         */
3744
3745         verifyDatabase();
3746
3747         std::ostringstream o(std::ios_base::binary);
3748
3749         o.write((char*)&version, 1);
3750
3751         // Write basic data
3752         block->serialize(o, version, true);
3753
3754         // Write block to database
3755
3756         std::string tmp = o.str();
3757         const char *bytes = tmp.c_str();
3758
3759         bool success = true;
3760         if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) {
3761                 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3762                 success = false;
3763         }
3764         if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) { // TODO this mught not be the right length
3765                 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3766                 success = false;
3767         }
3768         int written = sqlite3_step(m_database_write);
3769         if(written != SQLITE_DONE) {
3770                 errorstream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
3771                                 <<sqlite3_errmsg(m_database)<<std::endl;
3772                 success = false;
3773         }
3774         // Make ready for later reuse
3775         sqlite3_reset(m_database_write);
3776
3777         // We just wrote it to the disk so clear modified flag
3778         if (success)
3779                 block->resetModified();
3780 }
3781
3782 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3783 {
3784         DSTACK(__FUNCTION_NAME);
3785
3786         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3787         try{
3788
3789                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3790                 if(is.good() == false)
3791                         throw FileNotGoodException("Cannot open block file");
3792
3793                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3794                 v2s16 p2d(p3d.X, p3d.Z);
3795
3796                 assert(sector->getPos() == p2d);
3797
3798                 u8 version = SER_FMT_VER_INVALID;
3799                 is.read((char*)&version, 1);
3800
3801                 if(is.fail())
3802                         throw SerializationError("ServerMap::loadBlock(): Failed"
3803                                         " to read MapBlock version");
3804
3805                 /*u32 block_size = MapBlock::serializedLength(version);
3806                 SharedBuffer<u8> data(block_size);
3807                 is.read((char*)*data, block_size);*/
3808
3809                 // This will always return a sector because we're the server
3810                 //MapSector *sector = emergeSector(p2d);
3811
3812                 MapBlock *block = NULL;
3813                 bool created_new = false;
3814                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3815                 if(block == NULL)
3816                 {
3817                         block = sector->createBlankBlockNoInsert(p3d.Y);
3818                         created_new = true;
3819                 }
3820
3821                 // Read basic data
3822                 block->deSerialize(is, version, true);
3823
3824                 // If it's a new block, insert it to the map
3825                 if(created_new)
3826                         sector->insertBlock(block);
3827
3828                 /*
3829                         Save blocks loaded in old format in new format
3830                 */
3831
3832                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3833                 {
3834                         saveBlock(block);
3835
3836                         // Should be in database now, so delete the old file
3837                         fs::RecursiveDelete(fullpath);
3838                 }
3839
3840                 // We just loaded it from the disk, so it's up-to-date.
3841                 block->resetModified();
3842
3843         }
3844         catch(SerializationError &e)
3845         {
3846                 infostream<<"WARNING: Invalid block data on disk "
3847                                 <<"fullpath="<<fullpath
3848                                 <<" (SerializationError). "
3849                                 <<"what()="<<e.what()
3850                                 <<std::endl;
3851                                 //" Ignoring. A new one will be generated.
3852                 assert(0);
3853
3854                 // TODO: Backup file; name is in fullpath.
3855         }
3856 }
3857
3858 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3859 {
3860         DSTACK(__FUNCTION_NAME);
3861
3862         try {
3863                 std::istringstream is(*blob, std::ios_base::binary);
3864
3865                 u8 version = SER_FMT_VER_INVALID;
3866                 is.read((char*)&version, 1);
3867
3868                 if(is.fail())
3869                         throw SerializationError("ServerMap::loadBlock(): Failed"
3870                                         " to read MapBlock version");
3871
3872                 /*u32 block_size = MapBlock::serializedLength(version);
3873                 SharedBuffer<u8> data(block_size);
3874                 is.read((char*)*data, block_size);*/
3875
3876                 // This will always return a sector because we're the server
3877                 //MapSector *sector = emergeSector(p2d);
3878
3879                 MapBlock *block = NULL;
3880                 bool created_new = false;
3881                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3882                 if(block == NULL)
3883                 {
3884                         block = sector->createBlankBlockNoInsert(p3d.Y);
3885                         created_new = true;
3886                 }
3887
3888                 // Read basic data
3889                 block->deSerialize(is, version, true);
3890
3891                 // If it's a new block, insert it to the map
3892                 if(created_new)
3893                         sector->insertBlock(block);
3894
3895                 /*
3896                         Save blocks loaded in old format in new format
3897                 */
3898
3899                 //if(version < SER_FMT_VER_HIGHEST || save_after_load)
3900                 // Only save if asked to; no need to update version
3901                 if(save_after_load)
3902                         saveBlock(block);
3903
3904                 // We just loaded it from, so it's up-to-date.
3905                 block->resetModified();
3906
3907         }
3908         catch(SerializationError &e)
3909         {
3910                 errorstream<<"Invalid block data in database"
3911                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3912                                 <<" (SerializationError): "<<e.what()<<std::endl;
3913
3914                 // TODO: Block should be marked as invalid in memory so that it is
3915                 // not touched but the game can run
3916
3917                 if(g_settings->getBool("ignore_world_load_errors")){
3918                         errorstream<<"Ignoring block load error. Duck and cover! "
3919                                         <<"(ignore_world_load_errors)"<<std::endl;
3920                 } else {
3921                         throw SerializationError("Invalid block data in database");
3922                         //assert(0);
3923                 }
3924         }
3925 }
3926
3927 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3928 {
3929         DSTACK(__FUNCTION_NAME);
3930
3931         v2s16 p2d(blockpos.X, blockpos.Z);
3932
3933         if(!loadFromFolders()) {
3934                 verifyDatabase();
3935
3936                 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
3937                         infostream<<"WARNING: Could not bind block position for load: "
3938                                 <<sqlite3_errmsg(m_database)<<std::endl;
3939                 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
3940                         /*
3941                                 Make sure sector is loaded
3942                         */
3943                         MapSector *sector = createSector(p2d);
3944
3945                         /*
3946                                 Load block
3947                         */
3948                         const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
3949                         size_t len = sqlite3_column_bytes(m_database_read, 0);
3950
3951                         std::string datastr(data, len);
3952
3953                         loadBlock(&datastr, blockpos, sector, false);
3954
3955                         sqlite3_step(m_database_read);
3956                         // We should never get more than 1 row, so ok to reset
3957                         sqlite3_reset(m_database_read);
3958
3959                         return getBlockNoCreateNoEx(blockpos);
3960                 }
3961                 sqlite3_reset(m_database_read);
3962
3963                 // Not found in database, try the files
3964         }
3965
3966         // The directory layout we're going to load from.
3967         //  1 - original sectors/xxxxzzzz/
3968         //  2 - new sectors2/xxx/zzz/
3969         //  If we load from anything but the latest structure, we will
3970         //  immediately save to the new one, and remove the old.
3971         int loadlayout = 1;
3972         std::string sectordir1 = getSectorDir(p2d, 1);
3973         std::string sectordir;
3974         if(fs::PathExists(sectordir1))
3975         {
3976                 sectordir = sectordir1;
3977         }
3978         else
3979         {
3980                 loadlayout = 2;
3981                 sectordir = getSectorDir(p2d, 2);
3982         }
3983
3984         /*
3985                 Make sure sector is loaded
3986         */
3987         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3988         if(sector == NULL)
3989         {
3990                 try{
3991                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3992                 }
3993                 catch(InvalidFilenameException &e)
3994                 {
3995                         return NULL;
3996                 }
3997                 catch(FileNotGoodException &e)
3998                 {
3999                         return NULL;
4000                 }
4001                 catch(std::exception &e)
4002                 {
4003                         return NULL;
4004                 }
4005         }
4006
4007         /*
4008                 Make sure file exists
4009         */
4010
4011         std::string blockfilename = getBlockFilename(blockpos);
4012         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
4013                 return NULL;
4014
4015         /*
4016                 Load block and save it to the database
4017         */
4018         loadBlock(sectordir, blockfilename, sector, true);
4019         return getBlockNoCreateNoEx(blockpos);
4020 }
4021
4022 void ServerMap::PrintInfo(std::ostream &out)
4023 {
4024         out<<"ServerMap: ";
4025 }
4026
4027 /*
4028         MapVoxelManipulator
4029 */
4030
4031 MapVoxelManipulator::MapVoxelManipulator(Map *map)
4032 {
4033         m_map = map;
4034 }
4035
4036 MapVoxelManipulator::~MapVoxelManipulator()
4037 {
4038         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4039                         <<std::endl;*/
4040 }
4041
4042 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4043 {
4044         TimeTaker timer1("emerge", &emerge_time);
4045
4046         // Units of these are MapBlocks
4047         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4048         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4049
4050         VoxelArea block_area_nodes
4051                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4052
4053         addArea(block_area_nodes);
4054
4055         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4056         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4057         for(s32 x=p_min.X; x<=p_max.X; x++)
4058         {
4059                 u8 flags = 0;
4060                 MapBlock *block;
4061                 v3s16 p(x,y,z);
4062                 std::map<v3s16, u8>::iterator n;
4063                 n = m_loaded_blocks.find(p);
4064                 if(n != m_loaded_blocks.end())
4065                         continue;
4066
4067                 bool block_data_inexistent = false;
4068                 try
4069                 {
4070                         TimeTaker timer1("emerge load", &emerge_load_time);
4071
4072                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
4073                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4074                                         <<" wanted area: ";
4075                         a.print(infostream);
4076                         infostream<<std::endl;*/
4077
4078                         block = m_map->getBlockNoCreate(p);
4079                         if(block->isDummy())
4080                                 block_data_inexistent = true;
4081                         else
4082                                 block->copyTo(*this);
4083                 }
4084                 catch(InvalidPositionException &e)
4085                 {
4086                         block_data_inexistent = true;
4087                 }
4088
4089                 if(block_data_inexistent)
4090                 {
4091                         flags |= VMANIP_BLOCK_DATA_INEXIST;
4092
4093                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4094                         // Fill with VOXELFLAG_INEXISTENT
4095                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4096                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4097                         {
4098                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4099                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4100                         }
4101                 }
4102                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
4103                 {
4104                         // Mark that block was loaded as blank
4105                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
4106                 }*/
4107
4108                 m_loaded_blocks[p] = flags;
4109         }
4110
4111         //infostream<<"emerge done"<<std::endl;
4112 }
4113
4114 /*
4115         SUGG: Add an option to only update eg. water and air nodes.
4116               This will make it interfere less with important stuff if
4117                   run on background.
4118 */
4119 void MapVoxelManipulator::blitBack
4120                 (std::map<v3s16, MapBlock*> & modified_blocks)
4121 {
4122         if(m_area.getExtent() == v3s16(0,0,0))
4123                 return;
4124
4125         //TimeTaker timer1("blitBack");
4126
4127         /*infostream<<"blitBack(): m_loaded_blocks.size()="
4128                         <<m_loaded_blocks.size()<<std::endl;*/
4129
4130         /*
4131                 Initialize block cache
4132         */
4133         v3s16 blockpos_last;
4134         MapBlock *block = NULL;
4135         bool block_checked_in_modified = false;
4136
4137         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4138         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4139         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4140         {
4141                 v3s16 p(x,y,z);
4142
4143                 u8 f = m_flags[m_area.index(p)];
4144                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4145                         continue;
4146
4147                 MapNode &n = m_data[m_area.index(p)];
4148
4149                 v3s16 blockpos = getNodeBlockPos(p);
4150
4151                 try
4152                 {
4153                         // Get block
4154                         if(block == NULL || blockpos != blockpos_last){
4155                                 block = m_map->getBlockNoCreate(blockpos);
4156                                 blockpos_last = blockpos;
4157                                 block_checked_in_modified = false;
4158                         }
4159
4160                         // Calculate relative position in block
4161                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4162
4163                         // Don't continue if nothing has changed here
4164                         if(block->getNode(relpos) == n)
4165                                 continue;
4166
4167                         //m_map->setNode(m_area.MinEdge + p, n);
4168                         block->setNode(relpos, n);
4169
4170                         /*
4171                                 Make sure block is in modified_blocks
4172                         */
4173                         if(block_checked_in_modified == false)
4174                         {
4175                                 modified_blocks[blockpos] = block;
4176                                 block_checked_in_modified = true;
4177                         }
4178                 }
4179                 catch(InvalidPositionException &e)
4180                 {
4181                 }
4182         }
4183 }
4184
4185 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4186                 MapVoxelManipulator(map),
4187                 m_create_area(false)
4188 {
4189 }
4190
4191 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4192 {
4193 }
4194
4195 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4196 {
4197         // Just create the area so that it can be pointed to
4198         VoxelManipulator::emerge(a, caller_id);
4199 }
4200
4201 void ManualMapVoxelManipulator::initialEmerge(
4202                 v3s16 blockpos_min, v3s16 blockpos_max)
4203 {
4204         TimeTaker timer1("initialEmerge", &emerge_time);
4205
4206         // Units of these are MapBlocks
4207         v3s16 p_min = blockpos_min;
4208         v3s16 p_max = blockpos_max;
4209
4210         VoxelArea block_area_nodes
4211                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4212
4213         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4214         if(size_MB >= 1)
4215         {
4216                 infostream<<"initialEmerge: area: ";
4217                 block_area_nodes.print(infostream);
4218                 infostream<<" ("<<size_MB<<"MB)";
4219                 infostream<<std::endl;
4220         }
4221
4222         addArea(block_area_nodes);
4223
4224         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4225         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4226         for(s32 x=p_min.X; x<=p_max.X; x++)
4227         {
4228                 u8 flags = 0;
4229                 MapBlock *block;
4230                 v3s16 p(x,y,z);
4231                 std::map<v3s16, u8>::iterator n;
4232                 n = m_loaded_blocks.find(p);
4233                 if(n != m_loaded_blocks.end())
4234                         continue;
4235
4236                 bool block_data_inexistent = false;
4237                 try
4238                 {
4239                         TimeTaker timer1("emerge load", &emerge_load_time);
4240
4241                         block = m_map->getBlockNoCreate(p);
4242                         if(block->isDummy())
4243                                 block_data_inexistent = true;
4244                         else
4245                                 block->copyTo(*this);
4246                 }
4247                 catch(InvalidPositionException &e)
4248                 {
4249                         block_data_inexistent = true;
4250                 }
4251
4252                 if(block_data_inexistent)
4253                 {
4254                         flags |= VMANIP_BLOCK_DATA_INEXIST;
4255                         
4256                         /*
4257                                 Mark area inexistent
4258                         */
4259                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4260                         // Fill with VOXELFLAG_INEXISTENT
4261                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4262                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4263                         {
4264                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4265                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4266                         }
4267                 }
4268                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
4269                 {
4270                         // Mark that block was loaded as blank
4271                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
4272                 }*/
4273
4274                 m_loaded_blocks[p] = flags;
4275         }
4276 }
4277
4278 void ManualMapVoxelManipulator::blitBackAll(
4279                 std::map<v3s16, MapBlock*> * modified_blocks)
4280 {
4281         if(m_area.getExtent() == v3s16(0,0,0))
4282                 return;
4283
4284         /*
4285                 Copy data of all blocks
4286         */
4287         for(std::map<v3s16, u8>::iterator
4288                         i = m_loaded_blocks.begin();
4289                         i != m_loaded_blocks.end(); ++i)
4290         {
4291                 v3s16 p = i->first;
4292                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4293                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
4294                 if(existed == false)
4295                 {
4296                         continue;
4297                 }
4298
4299                 block->copyFrom(*this);
4300
4301                 if(modified_blocks)
4302                         (*modified_blocks)[p] = block;
4303         }
4304 }
4305
4306 //END