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