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