]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
Made unknown nodes stop falling nodes properly and shorten lines
[dragonfireclient.git] / src / map.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "map.h"
21 #include "mapsector.h"
22 #include "mapblock.h"
23 #include "main.h"
24 #include "filesys.h"
25 #include "voxel.h"
26 #include "porting.h"
27 #include "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                 if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
2140                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
2141                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
2142                         // it's perfectly safe to use liquid_kind here to determine the new node content.
2143                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
2144                 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
2145                         // liquid_kind is set properly, see above
2146                         new_node_content = liquid_kind;
2147                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
2148                 } else {
2149                         // no surrounding sources, so get the maximum level that can flow into this node
2150                         for (u16 i = 0; i < num_flows; i++) {
2151                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
2152                                 switch (flows[i].t) {
2153                                         case NEIGHBOR_UPPER:
2154                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
2155                                                         max_node_level = LIQUID_LEVEL_MAX;
2156                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
2157                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
2158                                                 } else if (nb_liquid_level > max_node_level)
2159                                                         max_node_level = nb_liquid_level;
2160                                                 break;
2161                                         case NEIGHBOR_LOWER:
2162                                                 break;
2163                                         case NEIGHBOR_SAME_LEVEL:
2164                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
2165                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
2166                                                         max_node_level = nb_liquid_level - 1;
2167                                                 }
2168                                                 break;
2169                                 }
2170                         }
2171
2172                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
2173                         if (viscosity > 1 && max_node_level != liquid_level) {
2174                                 // amount to gain, limited by viscosity
2175                                 // must be at least 1 in absolute value
2176                                 s8 level_inc = max_node_level - liquid_level;
2177                                 if (level_inc < -viscosity || level_inc > viscosity)
2178                                         new_node_level = liquid_level + level_inc/viscosity;
2179                                 else if (level_inc < 0)
2180                                         new_node_level = liquid_level - 1;
2181                                 else if (level_inc > 0)
2182                                         new_node_level = liquid_level + 1;
2183                                 if (new_node_level != max_node_level)
2184                                         must_reflow.push_back(p0);
2185                         } else
2186                                 new_node_level = max_node_level;
2187
2188                         u8 range = rangelim(nodemgr->get(liquid_kind).liquid_range, 0, LIQUID_LEVEL_MAX+1);
2189                         if (new_node_level >= (LIQUID_LEVEL_MAX+1-range))
2190                                 new_node_content = liquid_kind;
2191                         else
2192                                 new_node_content = CONTENT_AIR;
2193
2194                 }
2195
2196                 /*
2197                         check if anything has changed. if not, just continue with the next node.
2198                  */
2199                 if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
2200                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
2201                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
2202                                                                                  == flowing_down)))
2203                         continue;
2204
2205
2206                 /*
2207                         update the current node
2208                  */
2209                 MapNode n00 = n0;
2210                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
2211                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
2212                         // set level to last 3 bits, flowing down bit to 4th bit
2213                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
2214                 } else {
2215                         // set the liquid level and flow bit to 0
2216                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
2217                 }
2218                 n0.setContent(new_node_content);
2219
2220                 // Find out whether there is a suspect for this action
2221                 std::string suspect;
2222                 if(m_gamedef->rollback()){
2223                         suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
2224                 }
2225
2226                 if(!suspect.empty()){
2227                         // Blame suspect
2228                         RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
2229                         // Get old node for rollback
2230                         RollbackNode rollback_oldnode(this, p0, m_gamedef);
2231                         // Set node
2232                         setNode(p0, n0);
2233                         // Report
2234                         RollbackNode rollback_newnode(this, p0, m_gamedef);
2235                         RollbackAction action;
2236                         action.setSetNode(p0, rollback_oldnode, rollback_newnode);
2237                         m_gamedef->rollback()->reportAction(action);
2238                 } else {
2239                         // Set node
2240                         setNode(p0, n0);
2241                 }
2242
2243                 v3s16 blockpos = getNodeBlockPos(p0);
2244                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
2245                 if(block != NULL) {
2246                         modified_blocks[blockpos] =  block;
2247                         // If new or old node emits light, MapBlock requires lighting update
2248                         if(nodemgr->get(n0).light_source != 0 ||
2249                                         nodemgr->get(n00).light_source != 0)
2250                                 lighting_modified_blocks[block->getPos()] = block;
2251                 }
2252
2253                 /*
2254                         enqueue neighbors for update if neccessary
2255                  */
2256                 switch (nodemgr->get(n0.getContent()).liquid_type) {
2257                         case LIQUID_SOURCE:
2258                         case LIQUID_FLOWING:
2259                                 // make sure source flows into all neighboring nodes
2260                                 for (u16 i = 0; i < num_flows; i++)
2261                                         if (flows[i].t != NEIGHBOR_UPPER)
2262                                                 m_transforming_liquid.push_back(flows[i].p);
2263                                 for (u16 i = 0; i < num_airs; i++)
2264                                         if (airs[i].t != NEIGHBOR_UPPER)
2265                                                 m_transforming_liquid.push_back(airs[i].p);
2266                                 break;
2267                         case LIQUID_NONE:
2268                                 // this flow has turned to air; neighboring flows might need to do the same
2269                                 for (u16 i = 0; i < num_flows; i++)
2270                                         m_transforming_liquid.push_back(flows[i].p);
2271                                 break;
2272                 }
2273         }
2274         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
2275         while (must_reflow.size() > 0)
2276                 m_transforming_liquid.push_back(must_reflow.pop_front());
2277         updateLighting(lighting_modified_blocks, modified_blocks);
2278 }
2279
2280 NodeMetadata* Map::getNodeMetadata(v3s16 p)
2281 {
2282         v3s16 blockpos = getNodeBlockPos(p);
2283         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2284         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2285         if(!block){
2286                 infostream<<"Map::getNodeMetadata(): Need to emerge "
2287                                 <<PP(blockpos)<<std::endl;
2288                 block = emergeBlock(blockpos, false);
2289         }
2290         if(!block)
2291         {
2292                 infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
2293                                 <<std::endl;
2294                 return NULL;
2295         }
2296         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
2297         return meta;
2298 }
2299
2300 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
2301 {
2302         v3s16 blockpos = getNodeBlockPos(p);
2303         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2304         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2305         if(!block){
2306                 infostream<<"Map::setNodeMetadata(): Need to emerge "
2307                                 <<PP(blockpos)<<std::endl;
2308                 block = emergeBlock(blockpos, false);
2309         }
2310         if(!block)
2311         {
2312                 infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
2313                                 <<std::endl;
2314                 return;
2315         }
2316         block->m_node_metadata.set(p_rel, meta);
2317 }
2318
2319 void Map::removeNodeMetadata(v3s16 p)
2320 {
2321         v3s16 blockpos = getNodeBlockPos(p);
2322         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2323         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2324         if(block == NULL)
2325         {
2326                 infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
2327                                 <<std::endl;
2328                 return;
2329         }
2330         block->m_node_metadata.remove(p_rel);
2331 }
2332
2333 NodeTimer Map::getNodeTimer(v3s16 p)
2334 {
2335         v3s16 blockpos = getNodeBlockPos(p);
2336         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2337         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2338         if(!block){
2339                 infostream<<"Map::getNodeTimer(): Need to emerge "
2340                                 <<PP(blockpos)<<std::endl;
2341                 block = emergeBlock(blockpos, false);
2342         }
2343         if(!block)
2344         {
2345                 infostream<<"WARNING: Map::getNodeTimer(): Block not found"
2346                                 <<std::endl;
2347                 return NodeTimer();
2348         }
2349         NodeTimer t = block->m_node_timers.get(p_rel);
2350         return t;
2351 }
2352
2353 void Map::setNodeTimer(v3s16 p, NodeTimer t)
2354 {
2355         v3s16 blockpos = getNodeBlockPos(p);
2356         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2357         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2358         if(!block){
2359                 infostream<<"Map::setNodeTimer(): Need to emerge "
2360                                 <<PP(blockpos)<<std::endl;
2361                 block = emergeBlock(blockpos, false);
2362         }
2363         if(!block)
2364         {
2365                 infostream<<"WARNING: Map::setNodeTimer(): Block not found"
2366                                 <<std::endl;
2367                 return;
2368         }
2369         block->m_node_timers.set(p_rel, t);
2370 }
2371
2372 void Map::removeNodeTimer(v3s16 p)
2373 {
2374         v3s16 blockpos = getNodeBlockPos(p);
2375         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2376         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2377         if(block == NULL)
2378         {
2379                 infostream<<"WARNING: Map::removeNodeTimer(): Block not found"
2380                                 <<std::endl;
2381                 return;
2382         }
2383         block->m_node_timers.remove(p_rel);
2384 }
2385
2386 s16 Map::getHeat(v3s16 p)
2387 {
2388         MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
2389         if(block != NULL) {
2390                 return block->heat;
2391         }
2392         //errorstream << "No heat for " << p.X<<"," << p.Z << std::endl;
2393         return 0;
2394 }
2395
2396 s16 Map::getHumidity(v3s16 p)
2397 {
2398         MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
2399         if(block != NULL) {
2400                 return block->humidity;
2401         }
2402         //errorstream << "No humidity for " << p.X<<"," << p.Z << std::endl;
2403         return 0;
2404 }
2405
2406 /*
2407         ServerMap
2408 */
2409 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
2410         Map(dout_server, gamedef),
2411         m_seed(0),
2412         m_map_metadata_changed(true)
2413 {
2414         verbosestream<<__FUNCTION_NAME<<std::endl;
2415
2416         m_emerge = emerge;
2417         m_mgparams = m_emerge->getParamsFromSettings(g_settings);
2418         if (!m_mgparams)
2419                 m_mgparams = new MapgenV6Params();
2420
2421         m_seed = m_mgparams->seed;
2422
2423         if (g_settings->get("fixed_map_seed").empty())
2424         {
2425                 m_seed = (((u64)(myrand() & 0xffff) << 0)
2426                                 | ((u64)(myrand() & 0xffff) << 16)
2427                                 | ((u64)(myrand() & 0xffff) << 32)
2428                                 | ((u64)(myrand() & 0xffff) << 48));
2429                 m_mgparams->seed = m_seed;
2430         }
2431
2432         /*
2433                 Experimental and debug stuff
2434         */
2435
2436         {
2437         }
2438
2439         /*
2440                 Try to load map; if not found, create a new one.
2441         */
2442
2443         // Determine which database backend to use
2444         std::string conf_path = savedir + DIR_DELIM + "world.mt";
2445         Settings conf;
2446         bool succeeded = conf.readConfigFile(conf_path.c_str());
2447         if (!succeeded || !conf.exists("backend")) {
2448                 // fall back to sqlite3
2449                 dbase = new Database_SQLite3(this, savedir);
2450                 conf.set("backend", "sqlite3");
2451         } else {
2452                 std::string backend = conf.get("backend");
2453                 if (backend == "dummy")
2454                         dbase = new Database_Dummy(this);
2455                 else if (backend == "sqlite3")
2456                         dbase = new Database_SQLite3(this, savedir);
2457                 #if USE_LEVELDB
2458                 else if (backend == "leveldb")
2459                         dbase = new Database_LevelDB(this, savedir);
2460                 #endif
2461                 else
2462                         throw BaseException("Unknown map backend");
2463         }
2464
2465         m_savedir = savedir;
2466         m_map_saving_enabled = false;
2467
2468         try
2469         {
2470                 // If directory exists, check contents and load if possible
2471                 if(fs::PathExists(m_savedir))
2472                 {
2473                         // If directory is empty, it is safe to save into it.
2474                         if(fs::GetDirListing(m_savedir).size() == 0)
2475                         {
2476                                 infostream<<"ServerMap: Empty save directory is valid."
2477                                                 <<std::endl;
2478                                 m_map_saving_enabled = true;
2479                         }
2480                         else
2481                         {
2482                                 try{
2483                                         // Load map metadata (seed, chunksize)
2484                                         loadMapMeta();
2485                                 }
2486                                 catch(SettingNotFoundException &e){
2487                                         infostream<<"ServerMap:  Some metadata not found."
2488                                                           <<" Using default settings."<<std::endl;
2489                                 }
2490                                 catch(FileNotGoodException &e){
2491                                         infostream<<"WARNING: Could not load map metadata"
2492                                                         //<<" Disabling chunk-based generator."
2493                                                         <<std::endl;
2494                                         //m_chunksize = 0;
2495                                 }
2496
2497                                 infostream<<"ServerMap: Successfully loaded map "
2498                                                 <<"metadata from "<<savedir
2499                                                 <<", assuming valid save directory."
2500                                                 <<" seed="<<m_seed<<"."
2501                                                 <<std::endl;
2502
2503                                 m_map_saving_enabled = true;
2504                                 // Map loaded, not creating new one
2505                                 return;
2506                         }
2507                 }
2508                 // If directory doesn't exist, it is safe to save to it
2509                 else{
2510                         m_map_saving_enabled = true;
2511                 }
2512         }
2513         catch(std::exception &e)
2514         {
2515                 infostream<<"WARNING: ServerMap: Failed to load map from "<<savedir
2516                                 <<", exception: "<<e.what()<<std::endl;
2517                 infostream<<"Please remove the map or fix it."<<std::endl;
2518                 infostream<<"WARNING: Map saving will be disabled."<<std::endl;
2519         }
2520
2521         infostream<<"Initializing new map."<<std::endl;
2522
2523         // Create zero sector
2524         emergeSector(v2s16(0,0));
2525
2526         // Initially write whole map
2527         save(MOD_STATE_CLEAN);
2528 }
2529
2530 ServerMap::~ServerMap()
2531 {
2532         verbosestream<<__FUNCTION_NAME<<std::endl;
2533
2534         try
2535         {
2536                 if(m_map_saving_enabled)
2537                 {
2538                         // Save only changed parts
2539                         save(MOD_STATE_WRITE_AT_UNLOAD);
2540                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
2541                 }
2542                 else
2543                 {
2544                         infostream<<"ServerMap: Map not saved"<<std::endl;
2545                 }
2546         }
2547         catch(std::exception &e)
2548         {
2549                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
2550                                 <<", exception: "<<e.what()<<std::endl;
2551         }
2552
2553         /*
2554                 Close database if it was opened
2555         */
2556         delete(dbase);
2557
2558 #if 0
2559         /*
2560                 Free all MapChunks
2561         */
2562         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2563         for(; i.atEnd() == false; i++)
2564         {
2565                 MapChunk *chunk = i.getNode()->getValue();
2566                 delete chunk;
2567         }
2568 #endif
2569
2570         delete m_mgparams;
2571 }
2572
2573 bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
2574 {
2575         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2576         EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
2577
2578         s16 chunksize = m_mgparams->chunksize;
2579         s16 coffset = -chunksize / 2;
2580         v3s16 chunk_offset(coffset, coffset, coffset);
2581         v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
2582         v3s16 blockpos_min = blockpos_div * chunksize;
2583         v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
2584         blockpos_min += chunk_offset;
2585         blockpos_max += chunk_offset;
2586
2587         v3s16 extra_borders(1,1,1);
2588
2589         // Do nothing if not inside limits (+-1 because of neighbors)
2590         if(blockpos_over_limit(blockpos_min - extra_borders) ||
2591                 blockpos_over_limit(blockpos_max + extra_borders))
2592                 return false;
2593
2594         data->seed = m_seed;
2595         data->blockpos_min = blockpos_min;
2596         data->blockpos_max = blockpos_max;
2597         data->blockpos_requested = blockpos;
2598         data->nodedef = m_gamedef->ndef();
2599
2600         /*
2601                 Create the whole area of this and the neighboring blocks
2602         */
2603         {
2604                 //TimeTaker timer("initBlockMake() create area");
2605
2606                 for(s16 x=blockpos_min.X-extra_borders.X;
2607                                 x<=blockpos_max.X+extra_borders.X; x++)
2608                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2609                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2610                 {
2611                         v2s16 sectorpos(x, z);
2612                         // Sector metadata is loaded from disk if not already loaded.
2613                         ServerMapSector *sector = createSector(sectorpos);
2614                         assert(sector);
2615
2616                         for(s16 y=blockpos_min.Y-extra_borders.Y;
2617                                         y<=blockpos_max.Y+extra_borders.Y; y++)
2618                         {
2619                                 v3s16 p(x,y,z);
2620                                 //MapBlock *block = createBlock(p);
2621                                 // 1) get from memory, 2) load from disk
2622                                 MapBlock *block = emergeBlock(p, false);
2623                                 // 3) create a blank one
2624                                 if(block == NULL)
2625                                 {
2626                                         block = createBlock(p);
2627
2628                                         /*
2629                                                 Block gets sunlight if this is true.
2630
2631                                                 Refer to the map generator heuristics.
2632                                         */
2633                                         bool ug = m_emerge->isBlockUnderground(p);
2634                                         block->setIsUnderground(ug);
2635                                 }
2636
2637                                 // Lighting will not be valid after make_chunk is called
2638                                 block->setLightingExpired(true);
2639                                 // Lighting will be calculated
2640                                 //block->setLightingExpired(false);
2641                         }
2642                 }
2643         }
2644
2645         /*
2646                 Now we have a big empty area.
2647
2648                 Make a ManualMapVoxelManipulator that contains this and the
2649                 neighboring blocks
2650         */
2651
2652         // The area that contains this block and it's neighbors
2653         v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
2654         v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
2655
2656         data->vmanip = new ManualMapVoxelManipulator(this);
2657         //data->vmanip->setMap(this);
2658
2659         // Add the area
2660         {
2661                 //TimeTaker timer("initBlockMake() initialEmerge");
2662                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max, false);
2663         }
2664         
2665         // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE
2666 /*      for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
2667                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
2668                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
2669                                 core::map<v3s16, u8>::Node *n;
2670                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
2671                                 if (n == NULL)
2672                                         continue;
2673                                 u8 flags = n->getValue();
2674                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
2675                                 n->setValue(flags);
2676                         }
2677                 }
2678         }*/
2679
2680         // Data is ready now.
2681         return true;
2682 }
2683
2684 MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
2685                 std::map<v3s16, MapBlock*> &changed_blocks)
2686 {
2687         v3s16 blockpos_min = data->blockpos_min;
2688         v3s16 blockpos_max = data->blockpos_max;
2689         v3s16 blockpos_requested = data->blockpos_requested;
2690         /*infostream<<"finishBlockMake(): ("<<blockpos_requested.X<<","
2691                         <<blockpos_requested.Y<<","
2692                         <<blockpos_requested.Z<<")"<<std::endl;*/
2693
2694         v3s16 extra_borders(1,1,1);
2695
2696         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2697
2698         /*infostream<<"Resulting vmanip:"<<std::endl;
2699         data->vmanip.print(infostream);*/
2700
2701         // Make sure affected blocks are loaded
2702         for(s16 x=blockpos_min.X-extra_borders.X;
2703                         x<=blockpos_max.X+extra_borders.X; x++)
2704         for(s16 z=blockpos_min.Z-extra_borders.Z;
2705                         z<=blockpos_max.Z+extra_borders.Z; z++)
2706         for(s16 y=blockpos_min.Y-extra_borders.Y;
2707                         y<=blockpos_max.Y+extra_borders.Y; y++)
2708         {
2709                 v3s16 p(x, y, z);
2710                 // Load from disk if not already in memory
2711                 emergeBlock(p, false);
2712         }
2713
2714         /*
2715                 Blit generated stuff to map
2716                 NOTE: blitBackAll adds nearly everything to changed_blocks
2717         */
2718         {
2719                 // 70ms @cs=8
2720                 //TimeTaker timer("finishBlockMake() blitBackAll");
2721                 data->vmanip->blitBackAll(&changed_blocks);
2722         }
2723
2724         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
2725
2726         /*
2727                 Copy transforming liquid information
2728         */
2729         while(data->transforming_liquid.size() > 0)
2730         {
2731                 v3s16 p = data->transforming_liquid.pop_front();
2732                 m_transforming_liquid.push_back(p);
2733         }
2734
2735         /*
2736                 Do stuff in central blocks
2737         */
2738
2739         /*
2740                 Update lighting
2741         */
2742         {
2743 #if 0
2744                 TimeTaker t("finishBlockMake lighting update");
2745
2746                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2747
2748                 // Center blocks
2749                 for(s16 x=blockpos_min.X-extra_borders.X;
2750                                 x<=blockpos_max.X+extra_borders.X; x++)
2751                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2752                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2753                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2754                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2755                 {
2756                         v3s16 p(x, y, z);
2757                         MapBlock *block = getBlockNoCreateNoEx(p);
2758                         assert(block);
2759                         lighting_update_blocks.insert(block->getPos(), block);
2760                 }
2761
2762                 updateLighting(lighting_update_blocks, changed_blocks);
2763 #endif
2764
2765                 /*
2766                         Set lighting to non-expired state in all of them.
2767                         This is cheating, but it is not fast enough if all of them
2768                         would actually be updated.
2769                 */
2770                 for(s16 x=blockpos_min.X-extra_borders.X;
2771                                 x<=blockpos_max.X+extra_borders.X; x++)
2772                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2773                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2774                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2775                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2776                 {
2777                         v3s16 p(x, y, z);
2778                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2779                 }
2780
2781 #if 0
2782                 if(enable_mapgen_debug_info == false)
2783                         t.stop(true); // Hide output
2784 #endif
2785         }
2786
2787         /*
2788                 Go through changed blocks
2789         */
2790         for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
2791                         i != changed_blocks.end(); ++i)
2792         {
2793                 MapBlock *block = i->second;
2794                 assert(block);
2795                 /*
2796                         Update day/night difference cache of the MapBlocks
2797                 */
2798                 block->expireDayNightDiff();
2799                 /*
2800                         Set block as modified
2801                 */
2802                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2803                                 "finishBlockMake expireDayNightDiff");
2804         }
2805
2806         /*
2807                 Set central blocks as generated
2808         */
2809         for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)
2810         for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)
2811         for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++)
2812         {
2813                 v3s16 p(x, y, z);
2814                 MapBlock *block = getBlockNoCreateNoEx(p);
2815                 assert(block);
2816                 block->setGenerated(true);
2817         }
2818
2819         /*
2820                 Save changed parts of map
2821                 NOTE: Will be saved later.
2822         */
2823         //save(MOD_STATE_WRITE_AT_UNLOAD);
2824
2825         /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
2826                         <<","<<blockpos_requested.Y<<","
2827                         <<blockpos_requested.Z<<")"<<std::endl;*/
2828                         
2829         /*
2830                 Update weather data in blocks
2831         */
2832         ServerEnvironment *senv = &((Server *)m_gamedef)->getEnv();
2833         if (senv->m_use_weather) {
2834                 for(s16 x=blockpos_min.X-extra_borders.X;
2835                         x<=blockpos_max.X+extra_borders.X; x++)
2836                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2837                         z<=blockpos_max.Z+extra_borders.Z; z++)
2838                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2839                         y<=blockpos_max.Y+extra_borders.Y; y++)
2840                 {
2841                         v3s16 p(x, y, z);
2842                         updateBlockHeat(senv, p * MAP_BLOCKSIZE, NULL);
2843                         updateBlockHumidity(senv, p * MAP_BLOCKSIZE, NULL);
2844                 }
2845         } else {
2846                 for(s16 x=blockpos_min.X-extra_borders.X;
2847                         x<=blockpos_max.X+extra_borders.X; x++)
2848                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2849                         z<=blockpos_max.Z+extra_borders.Z; z++)
2850                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2851                         y<=blockpos_max.Y+extra_borders.Y; y++)
2852                 {
2853                         MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
2854                         block->heat     = HEAT_UNDEFINED;
2855                         block->humidity = HUMIDITY_UNDEFINED;
2856                         block->weather_update_time = 0;
2857                 }
2858         }
2859         
2860 #if 0
2861         if(enable_mapgen_debug_info)
2862         {
2863                 /*
2864                         Analyze resulting blocks
2865                 */
2866                 /*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
2867                 for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
2868                 for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
2869                 for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
2870                 for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
2871                 for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
2872                 {
2873                         v3s16 p = v3s16(x,y,z);
2874                         MapBlock *block = getBlockNoCreateNoEx(p);
2875                         char spos[20];
2876                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2877                         infostream<<"Generated "<<spos<<": "
2878                                         <<analyze_block(block)<<std::endl;
2879                 }
2880         }
2881 #endif
2882
2883         MapBlock *block = getBlockNoCreateNoEx(blockpos_requested);
2884         assert(block);
2885
2886         return block;
2887 }
2888
2889 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2890 {
2891         DSTACKF("%s: p2d=(%d,%d)",
2892                         __FUNCTION_NAME,
2893                         p2d.X, p2d.Y);
2894
2895         /*
2896                 Check if it exists already in memory
2897         */
2898         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2899         if(sector != NULL)
2900                 return sector;
2901
2902         /*
2903                 Try to load it from disk (with blocks)
2904         */
2905         //if(loadSectorFull(p2d) == true)
2906
2907         /*
2908                 Try to load metadata from disk
2909         */
2910 #if 0
2911         if(loadSectorMeta(p2d) == true)
2912         {
2913                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2914                 if(sector == NULL)
2915                 {
2916                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2917                         throw InvalidPositionException("");
2918                 }
2919                 return sector;
2920         }
2921 #endif
2922         /*
2923                 Do not create over-limit
2924         */
2925         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2926         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2927         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2928         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2929                 throw InvalidPositionException("createSector(): pos. over limit");
2930
2931         /*
2932                 Generate blank sector
2933         */
2934
2935         sector = new ServerMapSector(this, p2d, m_gamedef);
2936
2937         // Sector position on map in nodes
2938         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2939
2940         /*
2941                 Insert to container
2942         */
2943         m_sectors[p2d] = sector;
2944
2945         return sector;
2946 }
2947
2948 #if 0
2949 /*
2950         This is a quick-hand function for calling makeBlock().
2951 */
2952 MapBlock * ServerMap::generateBlock(
2953                 v3s16 p,
2954                 std::map<v3s16, MapBlock*> &modified_blocks
2955 )
2956 {
2957         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2958
2959         /*infostream<<"generateBlock(): "
2960                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2961                         <<std::endl;*/
2962
2963         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2964
2965         TimeTaker timer("generateBlock");
2966
2967         //MapBlock *block = original_dummy;
2968
2969         v2s16 p2d(p.X, p.Z);
2970         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2971
2972         /*
2973                 Do not generate over-limit
2974         */
2975         if(blockpos_over_limit(p))
2976         {
2977                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2978                 throw InvalidPositionException("generateBlock(): pos. over limit");
2979         }
2980
2981         /*
2982                 Create block make data
2983         */
2984         BlockMakeData data;
2985         initBlockMake(&data, p);
2986
2987         /*
2988                 Generate block
2989         */
2990         {
2991                 TimeTaker t("mapgen::make_block()");
2992                 mapgen->makeChunk(&data);
2993                 //mapgen::make_block(&data);
2994
2995                 if(enable_mapgen_debug_info == false)
2996                         t.stop(true); // Hide output
2997         }
2998
2999         /*
3000                 Blit data back on map, update lighting, add mobs and whatever this does
3001         */
3002         finishBlockMake(&data, modified_blocks);
3003
3004         /*
3005                 Get central block
3006         */
3007         MapBlock *block = getBlockNoCreateNoEx(p);
3008
3009 #if 0
3010         /*
3011                 Check result
3012         */
3013         if(block)
3014         {
3015                 bool erroneus_content = false;
3016                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3017                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3018                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3019                 {
3020                         v3s16 p(x0,y0,z0);
3021                         MapNode n = block->getNode(p);
3022                         if(n.getContent() == CONTENT_IGNORE)
3023                         {
3024                                 infostream<<"CONTENT_IGNORE at "
3025                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3026                                                 <<std::endl;
3027                                 erroneus_content = true;
3028                                 assert(0);
3029                         }
3030                 }
3031                 if(erroneus_content)
3032                 {
3033                         assert(0);
3034                 }
3035         }
3036 #endif
3037
3038 #if 0
3039         /*
3040                 Generate a completely empty block
3041         */
3042         if(block)
3043         {
3044                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
3045                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
3046                 {
3047                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
3048                         {
3049                                 MapNode n;
3050                                 n.setContent(CONTENT_AIR);
3051                                 block->setNode(v3s16(x0,y0,z0), n);
3052                         }
3053                 }
3054         }
3055 #endif
3056
3057         if(enable_mapgen_debug_info == false)
3058                 timer.stop(true); // Hide output
3059
3060         return block;
3061 }
3062 #endif
3063
3064 MapBlock * ServerMap::createBlock(v3s16 p)
3065 {
3066         DSTACKF("%s: p=(%d,%d,%d)",
3067                         __FUNCTION_NAME, p.X, p.Y, p.Z);
3068
3069         /*
3070                 Do not create over-limit
3071         */
3072         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3073         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3074         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3075         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3076         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
3077         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
3078                 throw InvalidPositionException("createBlock(): pos. over limit");
3079
3080         v2s16 p2d(p.X, p.Z);
3081         s16 block_y = p.Y;
3082         /*
3083                 This will create or load a sector if not found in memory.
3084                 If block exists on disk, it will be loaded.
3085
3086                 NOTE: On old save formats, this will be slow, as it generates
3087                       lighting on blocks for them.
3088         */
3089         ServerMapSector *sector;
3090         try{
3091                 sector = (ServerMapSector*)createSector(p2d);
3092                 assert(sector->getId() == MAPSECTOR_SERVER);
3093         }
3094         catch(InvalidPositionException &e)
3095         {
3096                 infostream<<"createBlock: createSector() failed"<<std::endl;
3097                 throw e;
3098         }
3099         /*
3100                 NOTE: This should not be done, or at least the exception
3101                 should not be passed on as std::exception, because it
3102                 won't be catched at all.
3103         */
3104         /*catch(std::exception &e)
3105         {
3106                 infostream<<"createBlock: createSector() failed: "
3107                                 <<e.what()<<std::endl;
3108                 throw e;
3109         }*/
3110
3111         /*
3112                 Try to get a block from the sector
3113         */
3114
3115         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
3116         if(block)
3117         {
3118                 if(block->isDummy())
3119                         block->unDummify();
3120                 return block;
3121         }
3122         // Create blank
3123         block = sector->createBlankBlock(block_y);
3124
3125         return block;
3126 }
3127
3128 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
3129 {
3130         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
3131                         __FUNCTION_NAME,
3132                         p.X, p.Y, p.Z, create_blank);
3133
3134         {
3135                 MapBlock *block = getBlockNoCreateNoEx(p);
3136                 if(block && block->isDummy() == false)
3137                         return block;
3138         }
3139
3140         {
3141                 MapBlock *block = loadBlock(p);
3142                 if(block)
3143                         return block;
3144         }
3145
3146         if (create_blank) {
3147                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
3148                 MapBlock *block = sector->createBlankBlock(p.Y);
3149
3150                 return block;
3151         }
3152         /*if(allow_generate)
3153         {
3154                 std::map<v3s16, MapBlock*> modified_blocks;
3155                 MapBlock *block = generateBlock(p, modified_blocks);
3156                 if(block)
3157                 {
3158                         MapEditEvent event;
3159                         event.type = MEET_OTHER;
3160                         event.p = p;
3161
3162                         // Copy modified_blocks to event
3163                         for(std::map<v3s16, MapBlock*>::iterator
3164                                         i = modified_blocks.begin();
3165                                         i != modified_blocks.end(); ++i)
3166                         {
3167                                 event.modified_blocks.insert(i->first);
3168                         }
3169
3170                         // Queue event
3171                         dispatchEvent(&event);
3172
3173                         return block;
3174                 }
3175         }*/
3176
3177         return NULL;
3178 }
3179
3180 s16 ServerMap::findGroundLevel(v2s16 p2d)
3181 {
3182 #if 0
3183         /*
3184                 Uh, just do something random...
3185         */
3186         // Find existing map from top to down
3187         s16 max=63;
3188         s16 min=-64;
3189         v3s16 p(p2d.X, max, p2d.Y);
3190         for(; p.Y>min; p.Y--)
3191         {
3192                 MapNode n = getNodeNoEx(p);
3193                 if(n.getContent() != CONTENT_IGNORE)
3194                         break;
3195         }
3196         if(p.Y == min)
3197                 goto plan_b;
3198         // If this node is not air, go to plan b
3199         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
3200                 goto plan_b;
3201         // Search existing walkable and return it
3202         for(; p.Y>min; p.Y--)
3203         {
3204                 MapNode n = getNodeNoEx(p);
3205                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
3206                         return p.Y;
3207         }
3208
3209         // Move to plan b
3210 plan_b:
3211 #endif
3212
3213         /*
3214                 Determine from map generator noise functions
3215         */
3216
3217         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
3218         return level;
3219
3220         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
3221         //return (s16)level;
3222 }
3223
3224 bool ServerMap::loadFromFolders() {
3225         if(!dbase->Initialized() && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) // ?
3226                 return true;
3227         return false;
3228 }
3229
3230 void ServerMap::createDirs(std::string path)
3231 {
3232         if(fs::CreateAllDirs(path) == false)
3233         {
3234                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
3235                                 <<"\""<<path<<"\""<<std::endl;
3236                 throw BaseException("ServerMap failed to create directory");
3237         }
3238 }
3239
3240 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
3241 {
3242         char cc[9];
3243         switch(layout)
3244         {
3245                 case 1:
3246                         snprintf(cc, 9, "%.4x%.4x",
3247                                 (unsigned int)pos.X&0xffff,
3248                                 (unsigned int)pos.Y&0xffff);
3249
3250                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
3251                 case 2:
3252                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
3253                                 (unsigned int)pos.X&0xfff,
3254                                 (unsigned int)pos.Y&0xfff);
3255
3256                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
3257                 default:
3258                         assert(false);
3259         }
3260 }
3261
3262 v2s16 ServerMap::getSectorPos(std::string dirname)
3263 {
3264         unsigned int x, y;
3265         int r;
3266         std::string component;
3267         fs::RemoveLastPathComponent(dirname, &component, 1);
3268         if(component.size() == 8)
3269         {
3270                 // Old layout
3271                 r = sscanf(component.c_str(), "%4x%4x", &x, &y);
3272         }
3273         else if(component.size() == 3)
3274         {
3275                 // New layout
3276                 fs::RemoveLastPathComponent(dirname, &component, 2);
3277                 r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
3278                 // Sign-extend the 12 bit values up to 16 bits...
3279                 if(x&0x800) x|=0xF000;
3280                 if(y&0x800) y|=0xF000;
3281         }
3282         else
3283         {
3284                 assert(false);
3285         }
3286         assert(r == 2);
3287         v2s16 pos((s16)x, (s16)y);
3288         return pos;
3289 }
3290
3291 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
3292 {
3293         v2s16 p2d = getSectorPos(sectordir);
3294
3295         if(blockfile.size() != 4){
3296                 throw InvalidFilenameException("Invalid block filename");
3297         }
3298         unsigned int y;
3299         int r = sscanf(blockfile.c_str(), "%4x", &y);
3300         if(r != 1)
3301                 throw InvalidFilenameException("Invalid block filename");
3302         return v3s16(p2d.X, y, p2d.Y);
3303 }
3304
3305 std::string ServerMap::getBlockFilename(v3s16 p)
3306 {
3307         char cc[5];
3308         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
3309         return cc;
3310 }
3311
3312 void ServerMap::save(ModifiedState save_level)
3313 {
3314         DSTACK(__FUNCTION_NAME);
3315         if(m_map_saving_enabled == false)
3316         {
3317                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
3318                 return;
3319         }
3320
3321         if(save_level == MOD_STATE_CLEAN)
3322                 infostream<<"ServerMap: Saving whole map, this can take time."
3323                                 <<std::endl;
3324
3325         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
3326         {
3327                 saveMapMeta();
3328         }
3329
3330         // Profile modified reasons
3331         Profiler modprofiler;
3332
3333         u32 sector_meta_count = 0;
3334         u32 block_count = 0;
3335         u32 block_count_all = 0; // Number of blocks in memory
3336
3337         // Don't do anything with sqlite unless something is really saved
3338         bool save_started = false;
3339
3340         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
3341                 i != m_sectors.end(); ++i)
3342         {
3343                 ServerMapSector *sector = (ServerMapSector*)i->second;
3344                 assert(sector->getId() == MAPSECTOR_SERVER);
3345
3346                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
3347                 {
3348                         saveSectorMeta(sector);
3349                         sector_meta_count++;
3350                 }
3351                 std::list<MapBlock*> blocks;
3352                 sector->getBlocks(blocks);
3353
3354                 for(std::list<MapBlock*>::iterator j = blocks.begin();
3355                         j != blocks.end(); ++j)
3356                 {
3357                         MapBlock *block = *j;
3358
3359                         block_count_all++;
3360
3361                         if(block->getModified() >= (u32)save_level)
3362                         {
3363                                 // Lazy beginSave()
3364                                 if(!save_started){
3365                                         beginSave();
3366                                         save_started = true;
3367                                 }
3368
3369                                 modprofiler.add(block->getModifiedReason(), 1);
3370
3371                                 saveBlock(block);
3372                                 block_count++;
3373
3374                                 /*infostream<<"ServerMap: Written block ("
3375                                                 <<block->getPos().X<<","
3376                                                 <<block->getPos().Y<<","
3377                                                 <<block->getPos().Z<<")"
3378                                                 <<std::endl;*/
3379                         }
3380                 }
3381         }
3382         if(save_started)
3383                 endSave();
3384
3385         /*
3386                 Only print if something happened or saved whole map
3387         */
3388         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
3389                         || block_count != 0)
3390         {
3391                 infostream<<"ServerMap: Written: "
3392                                 <<sector_meta_count<<" sector metadata files, "
3393                                 <<block_count<<" block files"
3394                                 <<", "<<block_count_all<<" blocks in memory."
3395                                 <<std::endl;
3396                 PrintInfo(infostream); // ServerMap/ClientMap:
3397                 infostream<<"Blocks modified by: "<<std::endl;
3398                 modprofiler.print(infostream);
3399         }
3400 }
3401
3402 void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst)
3403 {
3404         if(loadFromFolders()){
3405                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
3406                                 <<"all blocks that are stored in flat files"<<std::endl;
3407         }
3408         dbase->listAllLoadableBlocks(dst);
3409 }
3410
3411 void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst)
3412 {
3413         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
3414                 si != m_sectors.end(); ++si)
3415         {
3416                 MapSector *sector = si->second;
3417
3418                 std::list<MapBlock*> blocks;
3419                 sector->getBlocks(blocks);
3420
3421                 for(std::list<MapBlock*>::iterator i = blocks.begin();
3422                                 i != blocks.end(); ++i)
3423                 {
3424                         MapBlock *block = (*i);
3425                         v3s16 p = block->getPos();
3426                         dst.push_back(p);
3427                 }
3428         }
3429 }
3430
3431 void ServerMap::saveMapMeta()
3432 {
3433         DSTACK(__FUNCTION_NAME);
3434
3435         /*infostream<<"ServerMap::saveMapMeta(): "
3436                         <<"seed="<<m_seed
3437                         <<std::endl;*/
3438
3439         createDirs(m_savedir);
3440
3441         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3442         std::ostringstream ss(std::ios_base::binary);
3443
3444         Settings params;
3445
3446         m_emerge->setParamsToSettings(&params);
3447         params.writeLines(ss);
3448
3449         ss<<"[end_of_params]\n";
3450
3451         if(!fs::safeWriteToFile(fullpath, ss.str()))
3452         {
3453                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
3454                                 <<"could not write "<<fullpath<<std::endl;
3455                 throw FileNotGoodException("Cannot save chunk metadata");
3456         }
3457
3458         m_map_metadata_changed = false;
3459 }
3460
3461 void ServerMap::loadMapMeta()
3462 {
3463         DSTACK(__FUNCTION_NAME);
3464
3465         /*infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
3466                         <<std::endl;*/
3467
3468         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3469         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3470         if(is.good() == false)
3471         {
3472                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
3473                                 <<"could not open"<<fullpath<<std::endl;
3474                 throw FileNotGoodException("Cannot open map metadata");
3475         }
3476
3477         Settings params;
3478
3479         for(;;)
3480         {
3481                 if(is.eof())
3482                         throw SerializationError
3483                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3484                 std::string line;
3485                 std::getline(is, line);
3486                 std::string trimmedline = trim(line);
3487                 if(trimmedline == "[end_of_params]")
3488                         break;
3489                 params.parseConfigLine(line);
3490         }
3491         
3492         MapgenParams *mgparams;
3493         try {
3494                 mgparams = m_emerge->getParamsFromSettings(&params);
3495         } catch (SettingNotFoundException &e) {
3496                 infostream << "Couldn't get a setting from map_meta.txt: "
3497                                    << e.what() << std::endl;
3498                 mgparams = NULL;
3499         }
3500         
3501         if (mgparams) {
3502                 if (m_mgparams)
3503                         delete m_mgparams;
3504                 m_mgparams = mgparams;
3505                 m_seed = mgparams->seed;
3506         } else {
3507                 if (params.exists("seed")) {
3508                         m_seed = params.getU64("seed");
3509                         m_mgparams->seed = m_seed;
3510                 }
3511         }
3512
3513         verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
3514 }
3515
3516 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3517 {
3518         DSTACK(__FUNCTION_NAME);
3519         // Format used for writing
3520         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3521         // Get destination
3522         v2s16 pos = sector->getPos();
3523         std::string dir = getSectorDir(pos);
3524         createDirs(dir);
3525
3526         std::string fullpath = dir + DIR_DELIM + "meta";
3527         std::ostringstream ss(std::ios_base::binary);
3528
3529         sector->serialize(ss, version);
3530
3531         if(!fs::safeWriteToFile(fullpath, ss.str()))
3532                 throw FileNotGoodException("Cannot write sector metafile");
3533
3534         sector->differs_from_disk = false;
3535 }
3536
3537 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3538 {
3539         DSTACK(__FUNCTION_NAME);
3540         // Get destination
3541         v2s16 p2d = getSectorPos(sectordir);
3542
3543         ServerMapSector *sector = NULL;
3544
3545         std::string fullpath = sectordir + DIR_DELIM + "meta";
3546         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3547         if(is.good() == false)
3548         {
3549                 // If the directory exists anyway, it probably is in some old
3550                 // format. Just go ahead and create the sector.
3551                 if(fs::PathExists(sectordir))
3552                 {
3553                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3554                                         <<fullpath<<" doesn't exist but directory does."
3555                                         <<" Continuing with a sector with no metadata."
3556                                         <<std::endl;*/
3557                         sector = new ServerMapSector(this, p2d, m_gamedef);
3558                         m_sectors[p2d] = sector;
3559                 }
3560                 else
3561                 {
3562                         throw FileNotGoodException("Cannot open sector metafile");
3563                 }
3564         }
3565         else
3566         {
3567                 sector = ServerMapSector::deSerialize
3568                                 (is, this, p2d, m_sectors, m_gamedef);
3569                 if(save_after_load)
3570                         saveSectorMeta(sector);
3571         }
3572
3573         sector->differs_from_disk = false;
3574
3575         return sector;
3576 }
3577
3578 bool ServerMap::loadSectorMeta(v2s16 p2d)
3579 {
3580         DSTACK(__FUNCTION_NAME);
3581
3582         MapSector *sector = NULL;
3583
3584         // The directory layout we're going to load from.
3585         //  1 - original sectors/xxxxzzzz/
3586         //  2 - new sectors2/xxx/zzz/
3587         //  If we load from anything but the latest structure, we will
3588         //  immediately save to the new one, and remove the old.
3589         int loadlayout = 1;
3590         std::string sectordir1 = getSectorDir(p2d, 1);
3591         std::string sectordir;
3592         if(fs::PathExists(sectordir1))
3593         {
3594                 sectordir = sectordir1;
3595         }
3596         else
3597         {
3598                 loadlayout = 2;
3599                 sectordir = getSectorDir(p2d, 2);
3600         }
3601
3602         try{
3603                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3604         }
3605         catch(InvalidFilenameException &e)
3606         {
3607                 return false;
3608         }
3609         catch(FileNotGoodException &e)
3610         {
3611                 return false;
3612         }
3613         catch(std::exception &e)
3614         {
3615                 return false;
3616         }
3617
3618         return true;
3619 }
3620
3621 #if 0
3622 bool ServerMap::loadSectorFull(v2s16 p2d)
3623 {
3624         DSTACK(__FUNCTION_NAME);
3625
3626         MapSector *sector = NULL;
3627
3628         // The directory layout we're going to load from.
3629         //  1 - original sectors/xxxxzzzz/
3630         //  2 - new sectors2/xxx/zzz/
3631         //  If we load from anything but the latest structure, we will
3632         //  immediately save to the new one, and remove the old.
3633         int loadlayout = 1;
3634         std::string sectordir1 = getSectorDir(p2d, 1);
3635         std::string sectordir;
3636         if(fs::PathExists(sectordir1))
3637         {
3638                 sectordir = sectordir1;
3639         }
3640         else
3641         {
3642                 loadlayout = 2;
3643                 sectordir = getSectorDir(p2d, 2);
3644         }
3645
3646         try{
3647                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3648         }
3649         catch(InvalidFilenameException &e)
3650         {
3651                 return false;
3652         }
3653         catch(FileNotGoodException &e)
3654         {
3655                 return false;
3656         }
3657         catch(std::exception &e)
3658         {
3659                 return false;
3660         }
3661
3662         /*
3663                 Load blocks
3664         */
3665         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3666                         (sectordir);
3667         std::vector<fs::DirListNode>::iterator i2;
3668         for(i2=list2.begin(); i2!=list2.end(); i2++)
3669         {
3670                 // We want files
3671                 if(i2->dir)
3672                         continue;
3673                 try{
3674                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3675                 }
3676                 catch(InvalidFilenameException &e)
3677                 {
3678                         // This catches unknown crap in directory
3679                 }
3680         }
3681
3682         if(loadlayout != 2)
3683         {
3684                 infostream<<"Sector converted to new layout - deleting "<<
3685                         sectordir1<<std::endl;
3686                 fs::RecursiveDelete(sectordir1);
3687         }
3688
3689         return true;
3690 }
3691 #endif
3692
3693 void ServerMap::beginSave() {
3694         dbase->beginSave();
3695 }
3696
3697 void ServerMap::endSave() {
3698         dbase->endSave();
3699 }
3700
3701 void ServerMap::saveBlock(MapBlock *block)
3702 {
3703   dbase->saveBlock(block);
3704 }
3705
3706 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3707 {
3708         DSTACK(__FUNCTION_NAME);
3709
3710         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3711         try{
3712
3713                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3714                 if(is.good() == false)
3715                         throw FileNotGoodException("Cannot open block file");
3716
3717                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3718                 v2s16 p2d(p3d.X, p3d.Z);
3719
3720                 assert(sector->getPos() == p2d);
3721
3722                 u8 version = SER_FMT_VER_INVALID;
3723                 is.read((char*)&version, 1);
3724
3725                 if(is.fail())
3726                         throw SerializationError("ServerMap::loadBlock(): Failed"
3727                                         " to read MapBlock version");
3728
3729                 /*u32 block_size = MapBlock::serializedLength(version);
3730                 SharedBuffer<u8> data(block_size);
3731                 is.read((char*)*data, block_size);*/
3732
3733                 // This will always return a sector because we're the server
3734                 //MapSector *sector = emergeSector(p2d);
3735
3736                 MapBlock *block = NULL;
3737                 bool created_new = false;
3738                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3739                 if(block == NULL)
3740                 {
3741                         block = sector->createBlankBlockNoInsert(p3d.Y);
3742                         created_new = true;
3743                 }
3744
3745                 // Read basic data
3746                 block->deSerialize(is, version, true);
3747
3748                 // If it's a new block, insert it to the map
3749                 if(created_new)
3750                         sector->insertBlock(block);
3751
3752                 /*
3753                         Save blocks loaded in old format in new format
3754                 */
3755
3756                 if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
3757                 {
3758                         saveBlock(block);
3759
3760                         // Should be in database now, so delete the old file
3761                         fs::RecursiveDelete(fullpath);
3762                 }
3763
3764                 // We just loaded it from the disk, so it's up-to-date.
3765                 block->resetModified();
3766
3767         }
3768         catch(SerializationError &e)
3769         {
3770                 infostream<<"WARNING: Invalid block data on disk "
3771                                 <<"fullpath="<<fullpath
3772                                 <<" (SerializationError). "
3773                                 <<"what()="<<e.what()
3774                                 <<std::endl;
3775                                 // Ignoring. A new one will be generated.
3776                 assert(0);
3777
3778                 // TODO: Backup file; name is in fullpath.
3779         }
3780 }
3781
3782 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3783 {
3784         DSTACK(__FUNCTION_NAME);
3785
3786         try {
3787                 std::istringstream is(*blob, std::ios_base::binary);
3788
3789                 u8 version = SER_FMT_VER_INVALID;
3790                 is.read((char*)&version, 1);
3791
3792                 if(is.fail())
3793                         throw SerializationError("ServerMap::loadBlock(): Failed"
3794                                         " to read MapBlock version");
3795
3796                 /*u32 block_size = MapBlock::serializedLength(version);
3797                 SharedBuffer<u8> data(block_size);
3798                 is.read((char*)*data, block_size);*/
3799
3800                 // This will always return a sector because we're the server
3801                 //MapSector *sector = emergeSector(p2d);
3802
3803                 MapBlock *block = NULL;
3804                 bool created_new = false;
3805                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3806                 if(block == NULL)
3807                 {
3808                         block = sector->createBlankBlockNoInsert(p3d.Y);
3809                         created_new = true;
3810                 }
3811
3812                 // Read basic data
3813                 block->deSerialize(is, version, true);
3814
3815                 // If it's a new block, insert it to the map
3816                 if(created_new)
3817                         sector->insertBlock(block);
3818
3819                 /*
3820                         Save blocks loaded in old format in new format
3821                 */
3822
3823                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
3824                 // Only save if asked to; no need to update version
3825                 if(save_after_load)
3826                         saveBlock(block);
3827
3828                 // We just loaded it from, so it's up-to-date.
3829                 block->resetModified();
3830
3831         }
3832         catch(SerializationError &e)
3833         {
3834                 errorstream<<"Invalid block data in database"
3835                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3836                                 <<" (SerializationError): "<<e.what()<<std::endl;
3837
3838                 // TODO: Block should be marked as invalid in memory so that it is
3839                 // not touched but the game can run
3840
3841                 if(g_settings->getBool("ignore_world_load_errors")){
3842                         errorstream<<"Ignoring block load error. Duck and cover! "
3843                                         <<"(ignore_world_load_errors)"<<std::endl;
3844                 } else {
3845                         throw SerializationError("Invalid block data in database");
3846                         //assert(0);
3847                 }
3848         }
3849 }
3850
3851 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3852 {
3853         DSTACK(__FUNCTION_NAME);
3854
3855         v2s16 p2d(blockpos.X, blockpos.Z);
3856
3857         MapBlock *ret;
3858
3859         ret = dbase->loadBlock(blockpos);
3860         if (ret) return (ret);
3861         // Not found in database, try the files
3862
3863         // The directory layout we're going to load from.
3864         //  1 - original sectors/xxxxzzzz/
3865         //  2 - new sectors2/xxx/zzz/
3866         //  If we load from anything but the latest structure, we will
3867         //  immediately save to the new one, and remove the old.
3868         int loadlayout = 1;
3869         std::string sectordir1 = getSectorDir(p2d, 1);
3870         std::string sectordir;
3871         if(fs::PathExists(sectordir1))
3872         {
3873                 sectordir = sectordir1;
3874         }
3875         else
3876         {
3877                 loadlayout = 2;
3878                 sectordir = getSectorDir(p2d, 2);
3879         }
3880
3881         /*
3882                 Make sure sector is loaded
3883         */
3884         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3885         if(sector == NULL)
3886         {
3887                 try{
3888                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3889                 }
3890                 catch(InvalidFilenameException &e)
3891                 {
3892                         return NULL;
3893                 }
3894                 catch(FileNotGoodException &e)
3895                 {
3896                         return NULL;
3897                 }
3898                 catch(std::exception &e)
3899                 {
3900                         return NULL;
3901                 }
3902         }
3903
3904         /*
3905                 Make sure file exists
3906         */
3907
3908         std::string blockfilename = getBlockFilename(blockpos);
3909         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3910                 return NULL;
3911
3912         /*
3913                 Load block and save it to the database
3914         */
3915         loadBlock(sectordir, blockfilename, sector, true);
3916         return getBlockNoCreateNoEx(blockpos);
3917 }
3918
3919 void ServerMap::PrintInfo(std::ostream &out)
3920 {
3921         out<<"ServerMap: ";
3922 }
3923
3924 s16 ServerMap::updateBlockHeat(ServerEnvironment *env, v3s16 p, MapBlock *block)
3925 {
3926         u32 gametime = env->getGameTime();
3927         
3928         if (block) {
3929                 if (gametime - block->weather_update_time < 10)
3930                         return block->heat;
3931         } else {
3932                 block = getBlockNoCreateNoEx(getNodeBlockPos(p));
3933         }
3934
3935         f32 heat = m_emerge->biomedef->calcBlockHeat(p, m_seed,
3936                         env->getTimeOfDayF(), gametime * env->getTimeOfDaySpeed());
3937
3938         if(block) {
3939                 block->heat = heat;
3940                 block->weather_update_time = gametime;
3941         }
3942         return heat;
3943 }
3944
3945 s16 ServerMap::updateBlockHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block)
3946 {
3947         u32 gametime = env->getGameTime();
3948         
3949         if (block) {
3950                 if (gametime - block->weather_update_time < 10)
3951                         return block->humidity;
3952         } else {
3953                 block = getBlockNoCreateNoEx(getNodeBlockPos(p));
3954         }
3955
3956         f32 humidity = m_emerge->biomedef->calcBlockHumidity(p, m_seed,
3957                         env->getTimeOfDayF(), gametime * env->getTimeOfDaySpeed());
3958                         
3959         if(block) {
3960                 block->humidity = humidity;
3961                 block->weather_update_time = gametime;
3962         }
3963         return humidity;
3964 }
3965
3966 /*
3967         MapVoxelManipulator
3968 */
3969
3970 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3971 {
3972         m_map = map;
3973 }
3974
3975 MapVoxelManipulator::~MapVoxelManipulator()
3976 {
3977         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3978                         <<std::endl;*/
3979 }
3980
3981 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3982 {
3983         TimeTaker timer1("emerge", &emerge_time);
3984
3985         // Units of these are MapBlocks
3986         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3987         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3988
3989         VoxelArea block_area_nodes
3990                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3991
3992         addArea(block_area_nodes);
3993
3994         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3995         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3996         for(s32 x=p_min.X; x<=p_max.X; x++)
3997         {
3998                 u8 flags = 0;
3999                 MapBlock *block;
4000                 v3s16 p(x,y,z);
4001                 std::map<v3s16, u8>::iterator n;
4002                 n = m_loaded_blocks.find(p);
4003                 if(n != m_loaded_blocks.end())
4004                         continue;
4005
4006                 bool block_data_inexistent = false;
4007                 try
4008                 {
4009                         TimeTaker timer1("emerge load", &emerge_load_time);
4010
4011                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
4012                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4013                                         <<" wanted area: ";
4014                         a.print(infostream);
4015                         infostream<<std::endl;*/
4016
4017                         block = m_map->getBlockNoCreate(p);
4018                         if(block->isDummy())
4019                                 block_data_inexistent = true;
4020                         else
4021                                 block->copyTo(*this);
4022                 }
4023                 catch(InvalidPositionException &e)
4024                 {
4025                         block_data_inexistent = true;
4026                 }
4027
4028                 if(block_data_inexistent)
4029                 {
4030                         flags |= VMANIP_BLOCK_DATA_INEXIST;
4031
4032                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4033                         // Fill with VOXELFLAG_INEXISTENT
4034                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4035                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4036                         {
4037                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4038                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4039                         }
4040                 }
4041                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
4042                 {
4043                         // Mark that block was loaded as blank
4044                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
4045                 }*/
4046
4047                 m_loaded_blocks[p] = flags;
4048         }
4049
4050         //infostream<<"emerge done"<<std::endl;
4051 }
4052
4053 /*
4054         SUGG: Add an option to only update eg. water and air nodes.
4055               This will make it interfere less with important stuff if
4056                   run on background.
4057 */
4058 void MapVoxelManipulator::blitBack
4059                 (std::map<v3s16, MapBlock*> & modified_blocks)
4060 {
4061         if(m_area.getExtent() == v3s16(0,0,0))
4062                 return;
4063
4064         //TimeTaker timer1("blitBack");
4065
4066         /*infostream<<"blitBack(): m_loaded_blocks.size()="
4067                         <<m_loaded_blocks.size()<<std::endl;*/
4068
4069         /*
4070                 Initialize block cache
4071         */
4072         v3s16 blockpos_last;
4073         MapBlock *block = NULL;
4074         bool block_checked_in_modified = false;
4075
4076         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4077         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4078         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4079         {
4080                 v3s16 p(x,y,z);
4081
4082                 u8 f = m_flags[m_area.index(p)];
4083                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4084                         continue;
4085
4086                 MapNode &n = m_data[m_area.index(p)];
4087
4088                 v3s16 blockpos = getNodeBlockPos(p);
4089
4090                 try
4091                 {
4092                         // Get block
4093                         if(block == NULL || blockpos != blockpos_last){
4094                                 block = m_map->getBlockNoCreate(blockpos);
4095                                 blockpos_last = blockpos;
4096                                 block_checked_in_modified = false;
4097                         }
4098
4099                         // Calculate relative position in block
4100                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4101
4102                         // Don't continue if nothing has changed here
4103                         if(block->getNode(relpos) == n)
4104                                 continue;
4105
4106                         //m_map->setNode(m_area.MinEdge + p, n);
4107                         block->setNode(relpos, n);
4108
4109                         /*
4110                                 Make sure block is in modified_blocks
4111                         */
4112                         if(block_checked_in_modified == false)
4113                         {
4114                                 modified_blocks[blockpos] = block;
4115                                 block_checked_in_modified = true;
4116                         }
4117                 }
4118                 catch(InvalidPositionException &e)
4119                 {
4120                 }
4121         }
4122 }
4123
4124 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4125                 MapVoxelManipulator(map),
4126                 m_create_area(false)
4127 {
4128 }
4129
4130 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4131 {
4132 }
4133
4134 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4135 {
4136         // Just create the area so that it can be pointed to
4137         VoxelManipulator::emerge(a, caller_id);
4138 }
4139
4140 void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min,
4141                                                 v3s16 blockpos_max, bool load_if_inexistent)
4142 {
4143         TimeTaker timer1("initialEmerge", &emerge_time);
4144
4145         // Units of these are MapBlocks
4146         v3s16 p_min = blockpos_min;
4147         v3s16 p_max = blockpos_max;
4148
4149         VoxelArea block_area_nodes
4150                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4151
4152         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4153         if(size_MB >= 1)
4154         {
4155                 infostream<<"initialEmerge: area: ";
4156                 block_area_nodes.print(infostream);
4157                 infostream<<" ("<<size_MB<<"MB)";
4158                 infostream<<std::endl;
4159         }
4160
4161         addArea(block_area_nodes);
4162
4163         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4164         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4165         for(s32 x=p_min.X; x<=p_max.X; x++)
4166         {
4167                 u8 flags = 0;
4168                 MapBlock *block;
4169                 v3s16 p(x,y,z);
4170                 std::map<v3s16, u8>::iterator n;
4171                 n = m_loaded_blocks.find(p);
4172                 if(n != m_loaded_blocks.end())
4173                         continue;
4174
4175                 bool block_data_inexistent = false;
4176                 try
4177                 {
4178                         TimeTaker timer1("emerge load", &emerge_load_time);
4179
4180                         block = m_map->getBlockNoCreate(p);
4181                         if(block->isDummy())
4182                                 block_data_inexistent = true;
4183                         else
4184                                 block->copyTo(*this);
4185                 }
4186                 catch(InvalidPositionException &e)
4187                 {
4188                         block_data_inexistent = true;
4189                 }
4190
4191                 if(block_data_inexistent)
4192                 {
4193                         
4194                         if (load_if_inexistent) {
4195                                 ServerMap *svrmap = (ServerMap *)m_map;
4196                                 block = svrmap->emergeBlock(p, false);
4197                                 if (block == NULL)
4198                                         block = svrmap->createBlock(p);
4199                                 else
4200                                         block->copyTo(*this);
4201                         } else {
4202                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
4203                                 
4204                                 /*
4205                                         Mark area inexistent
4206                                 */
4207                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4208                                 // Fill with VOXELFLAG_INEXISTENT
4209                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4210                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4211                                 {
4212                                         s32 i = m_area.index(a.MinEdge.X,y,z);
4213                                         memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4214                                 }
4215                         }
4216                 }
4217                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
4218                 {
4219                         // Mark that block was loaded as blank
4220                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
4221                 }*/
4222
4223                 m_loaded_blocks[p] = flags;
4224         }
4225 }
4226
4227 void ManualMapVoxelManipulator::blitBackAll(
4228                 std::map<v3s16, MapBlock*> * modified_blocks)
4229 {
4230         if(m_area.getExtent() == v3s16(0,0,0))
4231                 return;
4232
4233         /*
4234                 Copy data of all blocks
4235         */
4236         for(std::map<v3s16, u8>::iterator
4237                         i = m_loaded_blocks.begin();
4238                         i != m_loaded_blocks.end(); ++i)
4239         {
4240                 v3s16 p = i->first;
4241                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4242                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
4243                 if(existed == false)
4244                 {
4245                         continue;
4246                 }
4247
4248                 block->copyFrom(*this);
4249
4250                 if(modified_blocks)
4251                         (*modified_blocks)[p] = block;
4252         }
4253 }
4254
4255 //END