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