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