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