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