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