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