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