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