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