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