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