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