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