]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
Replace std::list by std::vector into timerUpdate calls
[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                 std::list<MapBlock*> blocks;
1444                 sector->getBlocks(blocks);
1445
1446                 for(std::list<MapBlock*>::iterator i = blocks.begin();
1447                                 i != blocks.end(); ++i)
1448                 {
1449                         MapBlock *block = (*i);
1450
1451                         block->incrementUsageTimer(dtime);
1452
1453                         if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout)
1454                         {
1455                                 v3s16 p = block->getPos();
1456
1457                                 // Save if modified
1458                                 if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading)
1459                                 {
1460                                         modprofiler.add(block->getModifiedReason(), 1);
1461                                         if (!saveBlock(block))
1462                                                 continue;
1463                                         saved_blocks_count++;
1464                                 }
1465
1466                                 // Delete from memory
1467                                 sector->deleteBlock(block);
1468
1469                                 if(unloaded_blocks)
1470                                         unloaded_blocks->push_back(p);
1471
1472                                 deleted_blocks_count++;
1473                         }
1474                         else
1475                         {
1476                                 all_blocks_deleted = false;
1477                                 block_count_all++;
1478                         }
1479                 }
1480
1481                 if(all_blocks_deleted)
1482                 {
1483                         sector_deletion_queue.push_back(si->first);
1484                 }
1485         }
1486         endSave();
1487
1488         // Finally delete the empty sectors
1489         deleteSectors(sector_deletion_queue);
1490
1491         if(deleted_blocks_count != 0)
1492         {
1493                 PrintInfo(infostream); // ServerMap/ClientMap:
1494                 infostream<<"Unloaded "<<deleted_blocks_count
1495                                 <<" blocks from memory";
1496                 if(save_before_unloading)
1497                         infostream<<", of which "<<saved_blocks_count<<" were written";
1498                 infostream<<", "<<block_count_all<<" blocks in memory";
1499                 infostream<<"."<<std::endl;
1500                 if(saved_blocks_count != 0){
1501                         PrintInfo(infostream); // ServerMap/ClientMap:
1502                         infostream<<"Blocks modified by: "<<std::endl;
1503                         modprofiler.print(infostream);
1504                 }
1505         }
1506 }
1507
1508 void Map::unloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks)
1509 {
1510         timerUpdate(0.0, -1.0, unloaded_blocks);
1511 }
1512
1513 void Map::deleteSectors(std::list<v2s16> &list)
1514 {
1515         for(std::list<v2s16>::iterator j = list.begin();
1516                 j != list.end(); ++j)
1517         {
1518                 MapSector *sector = m_sectors[*j];
1519                 // If sector is in sector cache, remove it from there
1520                 if(m_sector_cache == sector)
1521                         m_sector_cache = NULL;
1522                 // Remove from map and delete
1523                 m_sectors.erase(*j);
1524                 delete sector;
1525         }
1526 }
1527
1528 #if 0
1529 void Map::unloadUnusedData(float timeout,
1530                 core::list<v3s16> *deleted_blocks)
1531 {
1532         core::list<v2s16> sector_deletion_queue;
1533         u32 deleted_blocks_count = 0;
1534         u32 saved_blocks_count = 0;
1535
1536         core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
1537         for(; si.atEnd() == false; si++)
1538         {
1539                 MapSector *sector = si.getNode()->getValue();
1540
1541                 bool all_blocks_deleted = true;
1542
1543                 core::list<MapBlock*> blocks;
1544                 sector->getBlocks(blocks);
1545                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1546                                 i != blocks.end(); i++)
1547                 {
1548                         MapBlock *block = (*i);
1549
1550                         if(block->getUsageTimer() > timeout)
1551                         {
1552                                 // Save if modified
1553                                 if(block->getModified() != MOD_STATE_CLEAN)
1554                                 {
1555                                         saveBlock(block);
1556                                         saved_blocks_count++;
1557                                 }
1558                                 // Delete from memory
1559                                 sector->deleteBlock(block);
1560                                 deleted_blocks_count++;
1561                         }
1562                         else
1563                         {
1564                                 all_blocks_deleted = false;
1565                         }
1566                 }
1567
1568                 if(all_blocks_deleted)
1569                 {
1570                         sector_deletion_queue.push_back(si.getNode()->getKey());
1571                 }
1572         }
1573
1574         deleteSectors(sector_deletion_queue);
1575
1576         infostream<<"Map: Unloaded "<<deleted_blocks_count<<" blocks from memory"
1577                         <<", of which "<<saved_blocks_count<<" were wr."
1578                         <<std::endl;
1579
1580         //return sector_deletion_queue.getSize();
1581         //return deleted_blocks_count;
1582 }
1583 #endif
1584
1585 void Map::PrintInfo(std::ostream &out)
1586 {
1587         out<<"Map: ";
1588 }
1589
1590 #define WATER_DROP_BOOST 4
1591
1592 enum NeighborType {
1593         NEIGHBOR_UPPER,
1594         NEIGHBOR_SAME_LEVEL,
1595         NEIGHBOR_LOWER
1596 };
1597 struct NodeNeighbor {
1598         MapNode n;
1599         NeighborType t;
1600         v3s16 p;
1601         bool l; //can liquid
1602
1603         NodeNeighbor()
1604                 : n(CONTENT_AIR)
1605         { }
1606
1607         NodeNeighbor(const MapNode &node, NeighborType n_type, v3s16 pos)
1608                 : n(node),
1609                   t(n_type),
1610                   p(pos)
1611         { }
1612 };
1613
1614 void Map::transforming_liquid_add(v3s16 p) {
1615         m_transforming_liquid.push_back(p);
1616 }
1617
1618 s32 Map::transforming_liquid_size() {
1619         return m_transforming_liquid.size();
1620 }
1621
1622 void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
1623 {
1624
1625         INodeDefManager *nodemgr = m_gamedef->ndef();
1626
1627         DSTACK(__FUNCTION_NAME);
1628         //TimeTaker timer("transformLiquids()");
1629
1630         u32 loopcount = 0;
1631         u32 initial_size = m_transforming_liquid.size();
1632
1633         /*if(initial_size != 0)
1634                 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1635
1636         // list of nodes that due to viscosity have not reached their max level height
1637         std::deque<v3s16> must_reflow;
1638
1639         // List of MapBlocks that will require a lighting update (due to lava)
1640         std::map<v3s16, MapBlock*> lighting_modified_blocks;
1641
1642         u32 liquid_loop_max = g_settings->getS32("liquid_loop_max");
1643         u32 loop_max = liquid_loop_max;
1644
1645 #if 0
1646
1647         /* If liquid_loop_max is not keeping up with the queue size increase
1648          * loop_max up to a maximum of liquid_loop_max * dedicated_server_step.
1649          */
1650         if (m_transforming_liquid.size() > loop_max * 2) {
1651                 // "Burst" mode
1652                 float server_step = g_settings->getFloat("dedicated_server_step");
1653                 if (m_transforming_liquid_loop_count_multiplier - 1.0 < server_step)
1654                         m_transforming_liquid_loop_count_multiplier *= 1.0 + server_step / 10;
1655         } else {
1656                 m_transforming_liquid_loop_count_multiplier = 1.0;
1657         }
1658
1659         loop_max *= m_transforming_liquid_loop_count_multiplier;
1660 #endif
1661
1662         while(m_transforming_liquid.size() != 0)
1663         {
1664                 // This should be done here so that it is done when continue is used
1665                 if(loopcount >= initial_size || loopcount >= loop_max)
1666                         break;
1667                 loopcount++;
1668
1669                 /*
1670                         Get a queued transforming liquid node
1671                 */
1672                 v3s16 p0 = m_transforming_liquid.front();
1673                 m_transforming_liquid.pop_front();
1674
1675                 MapNode n0 = getNodeNoEx(p0);
1676
1677                 /*
1678                         Collect information about current node
1679                  */
1680                 s8 liquid_level = -1;
1681                 content_t liquid_kind = CONTENT_IGNORE;
1682                 LiquidType liquid_type = nodemgr->get(n0).liquid_type;
1683                 switch (liquid_type) {
1684                         case LIQUID_SOURCE:
1685                                 liquid_level = LIQUID_LEVEL_SOURCE;
1686                                 liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing);
1687                                 break;
1688                         case LIQUID_FLOWING:
1689                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
1690                                 liquid_kind = n0.getContent();
1691                                 break;
1692                         case LIQUID_NONE:
1693                                 // if this is an air node, it *could* be transformed into a liquid. otherwise,
1694                                 // continue with the next node.
1695                                 if (n0.getContent() != CONTENT_AIR)
1696                                         continue;
1697                                 liquid_kind = CONTENT_AIR;
1698                                 break;
1699                 }
1700
1701                 /*
1702                         Collect information about the environment
1703                  */
1704                 const v3s16 *dirs = g_6dirs;
1705                 NodeNeighbor sources[6]; // surrounding sources
1706                 int num_sources = 0;
1707                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
1708                 int num_flows = 0;
1709                 NodeNeighbor airs[6]; // surrounding air
1710                 int num_airs = 0;
1711                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
1712                 int num_neutrals = 0;
1713                 bool flowing_down = false;
1714                 for (u16 i = 0; i < 6; i++) {
1715                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1716                         switch (i) {
1717                                 case 1:
1718                                         nt = NEIGHBOR_UPPER;
1719                                         break;
1720                                 case 4:
1721                                         nt = NEIGHBOR_LOWER;
1722                                         break;
1723                         }
1724                         v3s16 npos = p0 + dirs[i];
1725                         NodeNeighbor nb(getNodeNoEx(npos), nt, npos);
1726                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
1727                                 case LIQUID_NONE:
1728                                         if (nb.n.getContent() == CONTENT_AIR) {
1729                                                 airs[num_airs++] = nb;
1730                                                 // if the current node is a water source the neighbor
1731                                                 // should be enqueded for transformation regardless of whether the
1732                                                 // current node changes or not.
1733                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
1734                                                         m_transforming_liquid.push_back(npos);
1735                                                 // if the current node happens to be a flowing node, it will start to flow down here.
1736                                                 if (nb.t == NEIGHBOR_LOWER) {
1737                                                         flowing_down = true;
1738                                                 }
1739                                         } else {
1740                                                 neutrals[num_neutrals++] = nb;
1741                                         }
1742                                         break;
1743                                 case LIQUID_SOURCE:
1744                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1745                                         if (liquid_kind == CONTENT_AIR)
1746                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
1747                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
1748                                                 neutrals[num_neutrals++] = nb;
1749                                         } else {
1750                                                 // Do not count bottom source, it will screw things up
1751                                                 if(dirs[i].Y != -1)
1752                                                         sources[num_sources++] = nb;
1753                                         }
1754                                         break;
1755                                 case LIQUID_FLOWING:
1756                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1757                                         if (liquid_kind == CONTENT_AIR)
1758                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
1759                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
1760                                                 neutrals[num_neutrals++] = nb;
1761                                         } else {
1762                                                 flows[num_flows++] = nb;
1763                                                 if (nb.t == NEIGHBOR_LOWER)
1764                                                         flowing_down = true;
1765                                         }
1766                                         break;
1767                         }
1768                 }
1769
1770                 /*
1771                         decide on the type (and possibly level) of the current node
1772                  */
1773                 content_t new_node_content;
1774                 s8 new_node_level = -1;
1775                 s8 max_node_level = -1;
1776
1777                 u8 range = nodemgr->get(liquid_kind).liquid_range;
1778                 if (range > LIQUID_LEVEL_MAX+1)
1779                         range = LIQUID_LEVEL_MAX+1;
1780
1781                 if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
1782                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1783                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1784                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1785                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
1786                 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
1787                         // liquid_kind is set properly, see above
1788                         new_node_content = liquid_kind;
1789                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
1790                         if (new_node_level < (LIQUID_LEVEL_MAX+1-range))
1791                                 new_node_content = CONTENT_AIR;
1792                 } else {
1793                         // no surrounding sources, so get the maximum level that can flow into this node
1794                         for (u16 i = 0; i < num_flows; i++) {
1795                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1796                                 switch (flows[i].t) {
1797                                         case NEIGHBOR_UPPER:
1798                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
1799                                                         max_node_level = LIQUID_LEVEL_MAX;
1800                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1801                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
1802                                                 } else if (nb_liquid_level > max_node_level)
1803                                                         max_node_level = nb_liquid_level;
1804                                                 break;
1805                                         case NEIGHBOR_LOWER:
1806                                                 break;
1807                                         case NEIGHBOR_SAME_LEVEL:
1808                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1809                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
1810                                                         max_node_level = nb_liquid_level - 1;
1811                                                 }
1812                                                 break;
1813                                 }
1814                         }
1815
1816                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
1817                         if (viscosity > 1 && max_node_level != liquid_level) {
1818                                 // amount to gain, limited by viscosity
1819                                 // must be at least 1 in absolute value
1820                                 s8 level_inc = max_node_level - liquid_level;
1821                                 if (level_inc < -viscosity || level_inc > viscosity)
1822                                         new_node_level = liquid_level + level_inc/viscosity;
1823                                 else if (level_inc < 0)
1824                                         new_node_level = liquid_level - 1;
1825                                 else if (level_inc > 0)
1826                                         new_node_level = liquid_level + 1;
1827                                 if (new_node_level != max_node_level)
1828                                         must_reflow.push_back(p0);
1829                         } else
1830                                 new_node_level = max_node_level;
1831
1832                         if (max_node_level >= (LIQUID_LEVEL_MAX+1-range))
1833                                 new_node_content = liquid_kind;
1834                         else
1835                                 new_node_content = CONTENT_AIR;
1836
1837                 }
1838
1839                 /*
1840                         check if anything has changed. if not, just continue with the next node.
1841                  */
1842                 if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1843                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1844                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1845                                                                                  == flowing_down)))
1846                         continue;
1847
1848
1849                 /*
1850                         update the current node
1851                  */
1852                 MapNode n00 = n0;
1853                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1854                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
1855                         // set level to last 3 bits, flowing down bit to 4th bit
1856                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1857                 } else {
1858                         // set the liquid level and flow bit to 0
1859                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1860                 }
1861                 n0.setContent(new_node_content);
1862
1863                 // Find out whether there is a suspect for this action
1864                 std::string suspect;
1865                 if(m_gamedef->rollback()){
1866                         suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
1867                 }
1868
1869                 if(!suspect.empty()){
1870                         // Blame suspect
1871                         RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
1872                         // Get old node for rollback
1873                         RollbackNode rollback_oldnode(this, p0, m_gamedef);
1874                         // Set node
1875                         setNode(p0, n0);
1876                         // Report
1877                         RollbackNode rollback_newnode(this, p0, m_gamedef);
1878                         RollbackAction action;
1879                         action.setSetNode(p0, rollback_oldnode, rollback_newnode);
1880                         m_gamedef->rollback()->reportAction(action);
1881                 } else {
1882                         // Set node
1883                         setNode(p0, n0);
1884                 }
1885
1886                 v3s16 blockpos = getNodeBlockPos(p0);
1887                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1888                 if(block != NULL) {
1889                         modified_blocks[blockpos] =  block;
1890                         // If new or old node emits light, MapBlock requires lighting update
1891                         if(nodemgr->get(n0).light_source != 0 ||
1892                                         nodemgr->get(n00).light_source != 0)
1893                                 lighting_modified_blocks[block->getPos()] = block;
1894                 }
1895
1896                 /*
1897                         enqueue neighbors for update if neccessary
1898                  */
1899                 switch (nodemgr->get(n0.getContent()).liquid_type) {
1900                         case LIQUID_SOURCE:
1901                         case LIQUID_FLOWING:
1902                                 // make sure source flows into all neighboring nodes
1903                                 for (u16 i = 0; i < num_flows; i++)
1904                                         if (flows[i].t != NEIGHBOR_UPPER)
1905                                                 m_transforming_liquid.push_back(flows[i].p);
1906                                 for (u16 i = 0; i < num_airs; i++)
1907                                         if (airs[i].t != NEIGHBOR_UPPER)
1908                                                 m_transforming_liquid.push_back(airs[i].p);
1909                                 break;
1910                         case LIQUID_NONE:
1911                                 // this flow has turned to air; neighboring flows might need to do the same
1912                                 for (u16 i = 0; i < num_flows; i++)
1913                                         m_transforming_liquid.push_back(flows[i].p);
1914                                 break;
1915                 }
1916         }
1917         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1918
1919         for (std::deque<v3s16>::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter)
1920                 m_transforming_liquid.push_back(*iter);
1921
1922         updateLighting(lighting_modified_blocks, modified_blocks);
1923
1924
1925         /* ----------------------------------------------------------------------
1926          * Manage the queue so that it does not grow indefinately
1927          */
1928         u16 time_until_purge = g_settings->getU16("liquid_queue_purge_time");
1929
1930         if (time_until_purge == 0)
1931                 return; // Feature disabled
1932
1933         time_until_purge *= 1000;       // seconds -> milliseconds
1934
1935         u32 curr_time = getTime(PRECISION_MILLI);
1936         u32 prev_unprocessed = m_unprocessed_count;
1937         m_unprocessed_count = m_transforming_liquid.size();
1938
1939         // if unprocessed block count is decreasing or stable
1940         if (m_unprocessed_count <= prev_unprocessed) {
1941                 m_queue_size_timer_started = false;
1942         } else {
1943                 if (!m_queue_size_timer_started)
1944                         m_inc_trending_up_start_time = curr_time;
1945                 m_queue_size_timer_started = true;
1946         }
1947
1948         // Account for curr_time overflowing
1949         if (m_queue_size_timer_started && m_inc_trending_up_start_time > curr_time)
1950                 m_queue_size_timer_started = false;
1951
1952         /* If the queue has been growing for more than liquid_queue_purge_time seconds
1953          * and the number of unprocessed blocks is still > liquid_loop_max then we
1954          * cannot keep up; dump the oldest blocks from the queue so that the queue
1955          * has liquid_loop_max items in it
1956          */
1957         if (m_queue_size_timer_started
1958                         && curr_time - m_inc_trending_up_start_time > time_until_purge
1959                         && m_unprocessed_count > liquid_loop_max) {
1960
1961                 size_t dump_qty = m_unprocessed_count - liquid_loop_max;
1962
1963                 infostream << "transformLiquids(): DUMPING " << dump_qty
1964                            << " blocks from the queue" << std::endl;
1965
1966                 while (dump_qty--)
1967                         m_transforming_liquid.pop_front();
1968
1969                 m_queue_size_timer_started = false; // optimistically assume we can keep up now
1970                 m_unprocessed_count = m_transforming_liquid.size();
1971         }
1972 }
1973
1974 NodeMetadata *Map::getNodeMetadata(v3s16 p)
1975 {
1976         v3s16 blockpos = getNodeBlockPos(p);
1977         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1978         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1979         if(!block){
1980                 infostream<<"Map::getNodeMetadata(): Need to emerge "
1981                                 <<PP(blockpos)<<std::endl;
1982                 block = emergeBlock(blockpos, false);
1983         }
1984         if(!block){
1985                 infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
1986                                 <<std::endl;
1987                 return NULL;
1988         }
1989         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1990         return meta;
1991 }
1992
1993 bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1994 {
1995         v3s16 blockpos = getNodeBlockPos(p);
1996         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1997         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1998         if(!block){
1999                 infostream<<"Map::setNodeMetadata(): Need to emerge "
2000                                 <<PP(blockpos)<<std::endl;
2001                 block = emergeBlock(blockpos, false);
2002         }
2003         if(!block){
2004                 infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
2005                                 <<std::endl;
2006                 return false;
2007         }
2008         block->m_node_metadata.set(p_rel, meta);
2009         return true;
2010 }
2011
2012 void Map::removeNodeMetadata(v3s16 p)
2013 {
2014         v3s16 blockpos = getNodeBlockPos(p);
2015         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2016         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2017         if(block == NULL)
2018         {
2019                 infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
2020                                 <<std::endl;
2021                 return;
2022         }
2023         block->m_node_metadata.remove(p_rel);
2024 }
2025
2026 NodeTimer Map::getNodeTimer(v3s16 p)
2027 {
2028         v3s16 blockpos = getNodeBlockPos(p);
2029         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2030         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2031         if(!block){
2032                 infostream<<"Map::getNodeTimer(): Need to emerge "
2033                                 <<PP(blockpos)<<std::endl;
2034                 block = emergeBlock(blockpos, false);
2035         }
2036         if(!block){
2037                 infostream<<"WARNING: Map::getNodeTimer(): Block not found"
2038                                 <<std::endl;
2039                 return NodeTimer();
2040         }
2041         NodeTimer t = block->m_node_timers.get(p_rel);
2042         return t;
2043 }
2044
2045 void Map::setNodeTimer(v3s16 p, NodeTimer t)
2046 {
2047         v3s16 blockpos = getNodeBlockPos(p);
2048         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2049         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2050         if(!block){
2051                 infostream<<"Map::setNodeTimer(): Need to emerge "
2052                                 <<PP(blockpos)<<std::endl;
2053                 block = emergeBlock(blockpos, false);
2054         }
2055         if(!block){
2056                 infostream<<"WARNING: Map::setNodeTimer(): Block not found"
2057                                 <<std::endl;
2058                 return;
2059         }
2060         block->m_node_timers.set(p_rel, t);
2061 }
2062
2063 void Map::removeNodeTimer(v3s16 p)
2064 {
2065         v3s16 blockpos = getNodeBlockPos(p);
2066         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2067         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2068         if(block == NULL)
2069         {
2070                 infostream<<"WARNING: Map::removeNodeTimer(): Block not found"
2071                                 <<std::endl;
2072                 return;
2073         }
2074         block->m_node_timers.remove(p_rel);
2075 }
2076
2077 /*
2078         ServerMap
2079 */
2080 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
2081         Map(dout_server, gamedef),
2082         m_emerge(emerge),
2083         m_map_metadata_changed(true)
2084 {
2085         verbosestream<<__FUNCTION_NAME<<std::endl;
2086
2087         /*
2088                 Try to load map; if not found, create a new one.
2089         */
2090
2091         // Determine which database backend to use
2092         std::string conf_path = savedir + DIR_DELIM + "world.mt";
2093         Settings conf;
2094         bool succeeded = conf.readConfigFile(conf_path.c_str());
2095         if (!succeeded || !conf.exists("backend")) {
2096                 // fall back to sqlite3
2097                 dbase = new Database_SQLite3(this, savedir);
2098                 conf.set("backend", "sqlite3");
2099         } else {
2100                 std::string backend = conf.get("backend");
2101                 if (backend == "dummy")
2102                         dbase = new Database_Dummy(this);
2103                 else if (backend == "sqlite3")
2104                         dbase = new Database_SQLite3(this, savedir);
2105                 #if USE_LEVELDB
2106                 else if (backend == "leveldb")
2107                         dbase = new Database_LevelDB(this, savedir);
2108                 #endif
2109                 #if USE_REDIS
2110                 else if (backend == "redis")
2111                         dbase = new Database_Redis(this, savedir);
2112                 #endif
2113                 else
2114                         throw BaseException("Unknown map backend");
2115         }
2116
2117         m_savedir = savedir;
2118         m_map_saving_enabled = false;
2119
2120         try
2121         {
2122                 // If directory exists, check contents and load if possible
2123                 if(fs::PathExists(m_savedir))
2124                 {
2125                         // If directory is empty, it is safe to save into it.
2126                         if(fs::GetDirListing(m_savedir).size() == 0)
2127                         {
2128                                 infostream<<"ServerMap: Empty save directory is valid."
2129                                                 <<std::endl;
2130                                 m_map_saving_enabled = true;
2131                         }
2132                         else
2133                         {
2134                                 try{
2135                                         // Load map metadata (seed, chunksize)
2136                                         loadMapMeta();
2137                                 }
2138                                 catch(SettingNotFoundException &e){
2139                                         infostream<<"ServerMap:  Some metadata not found."
2140                                                           <<" Using default settings."<<std::endl;
2141                                 }
2142                                 catch(FileNotGoodException &e){
2143                                         infostream<<"WARNING: Could not load map metadata"
2144                                                         //<<" Disabling chunk-based generator."
2145                                                         <<std::endl;
2146                                         //m_chunksize = 0;
2147                                 }
2148
2149                                 infostream<<"ServerMap: Successfully loaded map "
2150                                                 <<"metadata from "<<savedir
2151                                                 <<", assuming valid save directory."
2152                                                 <<" seed="<< m_emerge->params.seed <<"."
2153                                                 <<std::endl;
2154
2155                                 m_map_saving_enabled = true;
2156                                 // Map loaded, not creating new one
2157                                 return;
2158                         }
2159                 }
2160                 // If directory doesn't exist, it is safe to save to it
2161                 else{
2162                         m_map_saving_enabled = true;
2163                 }
2164         }
2165         catch(std::exception &e)
2166         {
2167                 infostream<<"WARNING: ServerMap: Failed to load map from "<<savedir
2168                                 <<", exception: "<<e.what()<<std::endl;
2169                 infostream<<"Please remove the map or fix it."<<std::endl;
2170                 infostream<<"WARNING: Map saving will be disabled."<<std::endl;
2171         }
2172
2173         infostream<<"Initializing new map."<<std::endl;
2174
2175         // Create zero sector
2176         emergeSector(v2s16(0,0));
2177
2178         // Initially write whole map
2179         save(MOD_STATE_CLEAN);
2180 }
2181
2182 ServerMap::~ServerMap()
2183 {
2184         verbosestream<<__FUNCTION_NAME<<std::endl;
2185
2186         try
2187         {
2188                 if(m_map_saving_enabled)
2189                 {
2190                         // Save only changed parts
2191                         save(MOD_STATE_WRITE_AT_UNLOAD);
2192                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
2193                 }
2194                 else
2195                 {
2196                         infostream<<"ServerMap: Map not saved"<<std::endl;
2197                 }
2198         }
2199         catch(std::exception &e)
2200         {
2201                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
2202                                 <<", exception: "<<e.what()<<std::endl;
2203         }
2204
2205         /*
2206                 Close database if it was opened
2207         */
2208         delete dbase;
2209
2210 #if 0
2211         /*
2212                 Free all MapChunks
2213         */
2214         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2215         for(; i.atEnd() == false; i++)
2216         {
2217                 MapChunk *chunk = i.getNode()->getValue();
2218                 delete chunk;
2219         }
2220 #endif
2221 }
2222
2223 u64 ServerMap::getSeed()
2224 {
2225         return m_emerge->params.seed;
2226 }
2227
2228 s16 ServerMap::getWaterLevel()
2229 {
2230         return m_emerge->params.water_level;
2231 }
2232
2233 bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
2234 {
2235         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2236         EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
2237
2238         s16 chunksize = m_emerge->params.chunksize;
2239         s16 coffset = -chunksize / 2;
2240         v3s16 chunk_offset(coffset, coffset, coffset);
2241         v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
2242         v3s16 blockpos_min = blockpos_div * chunksize;
2243         v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
2244         blockpos_min += chunk_offset;
2245         blockpos_max += chunk_offset;
2246
2247         v3s16 extra_borders(1,1,1);
2248
2249         // Do nothing if not inside limits (+-1 because of neighbors)
2250         if(blockpos_over_limit(blockpos_min - extra_borders) ||
2251                 blockpos_over_limit(blockpos_max + extra_borders))
2252                 return false;
2253
2254         data->seed = m_emerge->params.seed;
2255         data->blockpos_min = blockpos_min;
2256         data->blockpos_max = blockpos_max;
2257         data->blockpos_requested = blockpos;
2258         data->nodedef = m_gamedef->ndef();
2259
2260         /*
2261                 Create the whole area of this and the neighboring blocks
2262         */
2263         {
2264                 //TimeTaker timer("initBlockMake() create area");
2265
2266                 for(s16 x=blockpos_min.X-extra_borders.X;
2267                                 x<=blockpos_max.X+extra_borders.X; x++)
2268                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2269                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2270                 {
2271                         v2s16 sectorpos(x, z);
2272                         // Sector metadata is loaded from disk if not already loaded.
2273                         ServerMapSector *sector = createSector(sectorpos);
2274                         assert(sector);
2275                         (void) sector;
2276
2277                         for(s16 y=blockpos_min.Y-extra_borders.Y;
2278                                         y<=blockpos_max.Y+extra_borders.Y; y++)
2279                         {
2280                                 v3s16 p(x,y,z);
2281                                 //MapBlock *block = createBlock(p);
2282                                 // 1) get from memory, 2) load from disk
2283                                 MapBlock *block = emergeBlock(p, false);
2284                                 // 3) create a blank one
2285                                 if(block == NULL)
2286                                 {
2287                                         block = createBlock(p);
2288
2289                                         /*
2290                                                 Block gets sunlight if this is true.
2291
2292                                                 Refer to the map generator heuristics.
2293                                         */
2294                                         bool ug = m_emerge->isBlockUnderground(p);
2295                                         block->setIsUnderground(ug);
2296                                 }
2297
2298                                 // Lighting will not be valid after make_chunk is called
2299                                 block->setLightingExpired(true);
2300                                 // Lighting will be calculated
2301                                 //block->setLightingExpired(false);
2302                         }
2303                 }
2304         }
2305
2306         /*
2307                 Now we have a big empty area.
2308
2309                 Make a ManualMapVoxelManipulator that contains this and the
2310                 neighboring blocks
2311         */
2312
2313         // The area that contains this block and it's neighbors
2314         v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
2315         v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
2316
2317         data->vmanip = new MMVManip(this);
2318         //data->vmanip->setMap(this);
2319
2320         // Add the area
2321         {
2322                 //TimeTaker timer("initBlockMake() initialEmerge");
2323                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2324         }
2325
2326         // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE
2327 /*      for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
2328                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
2329                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
2330                                 core::map<v3s16, u8>::Node *n;
2331                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
2332                                 if (n == NULL)
2333                                         continue;
2334                                 u8 flags = n->getValue();
2335                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
2336                                 n->setValue(flags);
2337                         }
2338                 }
2339         }*/
2340
2341         // Data is ready now.
2342         return true;
2343 }
2344
2345 void ServerMap::finishBlockMake(BlockMakeData *data,
2346                 std::map<v3s16, MapBlock*> &changed_blocks)
2347 {
2348         v3s16 blockpos_min = data->blockpos_min;
2349         v3s16 blockpos_max = data->blockpos_max;
2350         v3s16 blockpos_requested = data->blockpos_requested;
2351         /*infostream<<"finishBlockMake(): ("<<blockpos_requested.X<<","
2352                         <<blockpos_requested.Y<<","
2353                         <<blockpos_requested.Z<<")"<<std::endl;*/
2354
2355         v3s16 extra_borders(1,1,1);
2356
2357         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2358
2359         /*infostream<<"Resulting vmanip:"<<std::endl;
2360         data->vmanip.print(infostream);*/
2361
2362         // Make sure affected blocks are loaded
2363         for(s16 x=blockpos_min.X-extra_borders.X;
2364                         x<=blockpos_max.X+extra_borders.X; x++)
2365         for(s16 z=blockpos_min.Z-extra_borders.Z;
2366                         z<=blockpos_max.Z+extra_borders.Z; z++)
2367         for(s16 y=blockpos_min.Y-extra_borders.Y;
2368                         y<=blockpos_max.Y+extra_borders.Y; y++)
2369         {
2370                 v3s16 p(x, y, z);
2371                 // Load from disk if not already in memory
2372                 emergeBlock(p, false);
2373         }
2374
2375         /*
2376                 Blit generated stuff to map
2377                 NOTE: blitBackAll adds nearly everything to changed_blocks
2378         */
2379         {
2380                 // 70ms @cs=8
2381                 //TimeTaker timer("finishBlockMake() blitBackAll");
2382                 data->vmanip->blitBackAll(&changed_blocks);
2383         }
2384
2385         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
2386
2387         /*
2388                 Copy transforming liquid information
2389         */
2390         while(data->transforming_liquid.size() > 0)
2391         {
2392                 m_transforming_liquid.push_back(data->transforming_liquid.front());
2393                 data->transforming_liquid.pop_front();
2394         }
2395
2396         /*
2397                 Do stuff in central blocks
2398         */
2399
2400         /*
2401                 Update lighting
2402         */
2403         {
2404 #if 0
2405                 TimeTaker t("finishBlockMake lighting update");
2406
2407                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2408
2409                 // Center blocks
2410                 for(s16 x=blockpos_min.X-extra_borders.X;
2411                                 x<=blockpos_max.X+extra_borders.X; x++)
2412                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2413                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2414                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2415                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2416                 {
2417                         v3s16 p(x, y, z);
2418                         MapBlock *block = getBlockNoCreateNoEx(p);
2419                         assert(block);
2420                         lighting_update_blocks.insert(block->getPos(), block);
2421                 }
2422
2423                 updateLighting(lighting_update_blocks, changed_blocks);
2424 #endif
2425
2426                 /*
2427                         Set lighting to non-expired state in all of them.
2428                         This is cheating, but it is not fast enough if all of them
2429                         would actually be updated.
2430                 */
2431                 for(s16 x=blockpos_min.X-extra_borders.X;
2432                                 x<=blockpos_max.X+extra_borders.X; x++)
2433                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2434                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2435                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2436                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2437                 {
2438                         v3s16 p(x, y, z);
2439                         MapBlock * block = getBlockNoCreateNoEx(p);
2440                         if (block != NULL)
2441                                 block->setLightingExpired(false);
2442                 }
2443
2444 #if 0
2445                 if(enable_mapgen_debug_info == false)
2446                         t.stop(true); // Hide output
2447 #endif
2448         }
2449
2450         /*
2451                 Go through changed blocks
2452         */
2453         for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
2454                         i != changed_blocks.end(); ++i)
2455         {
2456                 MapBlock *block = i->second;
2457                 if (!block)
2458                         continue;
2459                 /*
2460                         Update day/night difference cache of the MapBlocks
2461                 */
2462                 block->expireDayNightDiff();
2463                 /*
2464                         Set block as modified
2465                 */
2466                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2467                                 "finishBlockMake expireDayNightDiff");
2468         }
2469
2470         /*
2471                 Set central blocks as generated
2472         */
2473         for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)
2474         for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)
2475         for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++)
2476         {
2477                 v3s16 p(x, y, z);
2478                 MapBlock *block = getBlockNoCreateNoEx(p);
2479                 if (!block)
2480                         continue;
2481                 block->setGenerated(true);
2482         }
2483
2484         /*
2485                 Save changed parts of map
2486                 NOTE: Will be saved later.
2487         */
2488         //save(MOD_STATE_WRITE_AT_UNLOAD);
2489
2490         /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
2491                         <<","<<blockpos_requested.Y<<","
2492                         <<blockpos_requested.Z<<")"<<std::endl;*/
2493
2494
2495 #if 0
2496         if(enable_mapgen_debug_info)
2497         {
2498                 /*
2499                         Analyze resulting blocks
2500                 */
2501                 /*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
2502                 for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
2503                 for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
2504                 for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
2505                 for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
2506                 for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
2507                 {
2508                         v3s16 p = v3s16(x,y,z);
2509                         MapBlock *block = getBlockNoCreateNoEx(p);
2510                         char spos[20];
2511                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2512                         infostream<<"Generated "<<spos<<": "
2513                                         <<analyze_block(block)<<std::endl;
2514                 }
2515         }
2516 #endif
2517
2518         getBlockNoCreateNoEx(blockpos_requested);
2519 }
2520
2521 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2522 {
2523         DSTACKF("%s: p2d=(%d,%d)",
2524                         __FUNCTION_NAME,
2525                         p2d.X, p2d.Y);
2526
2527         /*
2528                 Check if it exists already in memory
2529         */
2530         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2531         if(sector != NULL)
2532                 return sector;
2533
2534         /*
2535                 Try to load it from disk (with blocks)
2536         */
2537         //if(loadSectorFull(p2d) == true)
2538
2539         /*
2540                 Try to load metadata from disk
2541         */
2542 #if 0
2543         if(loadSectorMeta(p2d) == true)
2544         {
2545                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2546                 if(sector == NULL)
2547                 {
2548                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2549                         throw InvalidPositionException("");
2550                 }
2551                 return sector;
2552         }
2553 #endif
2554         /*
2555                 Do not create over-limit
2556         */
2557         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2558         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2559         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2560         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2561                 throw InvalidPositionException("createSector(): pos. over limit");
2562
2563         /*
2564                 Generate blank sector
2565         */
2566
2567         sector = new ServerMapSector(this, p2d, m_gamedef);
2568
2569         // Sector position on map in nodes
2570         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2571
2572         /*
2573                 Insert to container
2574         */
2575         m_sectors[p2d] = sector;
2576
2577         return sector;
2578 }
2579
2580 #if 0
2581 /*
2582         This is a quick-hand function for calling makeBlock().
2583 */
2584 MapBlock * ServerMap::generateBlock(
2585                 v3s16 p,
2586                 std::map<v3s16, MapBlock*> &modified_blocks
2587 )
2588 {
2589         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2590
2591         /*infostream<<"generateBlock(): "
2592                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2593                         <<std::endl;*/
2594
2595         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2596
2597         TimeTaker timer("generateBlock");
2598
2599         //MapBlock *block = original_dummy;
2600
2601         v2s16 p2d(p.X, p.Z);
2602         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2603
2604         /*
2605                 Do not generate over-limit
2606         */
2607         if(blockpos_over_limit(p))
2608         {
2609                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2610                 throw InvalidPositionException("generateBlock(): pos. over limit");
2611         }
2612
2613         /*
2614                 Create block make data
2615         */
2616         BlockMakeData data;
2617         initBlockMake(&data, p);
2618
2619         /*
2620                 Generate block
2621         */
2622         {
2623                 TimeTaker t("mapgen::make_block()");
2624                 mapgen->makeChunk(&data);
2625                 //mapgen::make_block(&data);
2626
2627                 if(enable_mapgen_debug_info == false)
2628                         t.stop(true); // Hide output
2629         }
2630
2631         /*
2632                 Blit data back on map, update lighting, add mobs and whatever this does
2633         */
2634         finishBlockMake(&data, modified_blocks);
2635
2636         /*
2637                 Get central block
2638         */
2639         MapBlock *block = getBlockNoCreateNoEx(p);
2640
2641 #if 0
2642         /*
2643                 Check result
2644         */
2645         if(block)
2646         {
2647                 bool erroneus_content = false;
2648                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2649                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2650                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2651                 {
2652                         v3s16 p(x0,y0,z0);
2653                         MapNode n = block->getNode(p);
2654                         if(n.getContent() == CONTENT_IGNORE)
2655                         {
2656                                 infostream<<"CONTENT_IGNORE at "
2657                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2658                                                 <<std::endl;
2659                                 erroneus_content = true;
2660                                 assert(0);
2661                         }
2662                 }
2663                 if(erroneus_content)
2664                 {
2665                         assert(0);
2666                 }
2667         }
2668 #endif
2669
2670 #if 0
2671         /*
2672                 Generate a completely empty block
2673         */
2674         if(block)
2675         {
2676                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2677                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2678                 {
2679                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2680                         {
2681                                 MapNode n;
2682                                 n.setContent(CONTENT_AIR);
2683                                 block->setNode(v3s16(x0,y0,z0), n);
2684                         }
2685                 }
2686         }
2687 #endif
2688
2689         if(enable_mapgen_debug_info == false)
2690                 timer.stop(true); // Hide output
2691
2692         return block;
2693 }
2694 #endif
2695
2696 MapBlock * ServerMap::createBlock(v3s16 p)
2697 {
2698         DSTACKF("%s: p=(%d,%d,%d)",
2699                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2700
2701         /*
2702                 Do not create over-limit
2703         */
2704         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2705         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2706         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2707         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2708         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2709         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2710                 throw InvalidPositionException("createBlock(): pos. over limit");
2711
2712         v2s16 p2d(p.X, p.Z);
2713         s16 block_y = p.Y;
2714         /*
2715                 This will create or load a sector if not found in memory.
2716                 If block exists on disk, it will be loaded.
2717
2718                 NOTE: On old save formats, this will be slow, as it generates
2719                       lighting on blocks for them.
2720         */
2721         ServerMapSector *sector;
2722         try{
2723                 sector = (ServerMapSector*)createSector(p2d);
2724                 assert(sector->getId() == MAPSECTOR_SERVER);
2725         }
2726         catch(InvalidPositionException &e)
2727         {
2728                 infostream<<"createBlock: createSector() failed"<<std::endl;
2729                 throw e;
2730         }
2731         /*
2732                 NOTE: This should not be done, or at least the exception
2733                 should not be passed on as std::exception, because it
2734                 won't be catched at all.
2735         */
2736         /*catch(std::exception &e)
2737         {
2738                 infostream<<"createBlock: createSector() failed: "
2739                                 <<e.what()<<std::endl;
2740                 throw e;
2741         }*/
2742
2743         /*
2744                 Try to get a block from the sector
2745         */
2746
2747         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2748         if(block)
2749         {
2750                 if(block->isDummy())
2751                         block->unDummify();
2752                 return block;
2753         }
2754         // Create blank
2755         block = sector->createBlankBlock(block_y);
2756
2757         return block;
2758 }
2759
2760 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
2761 {
2762         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
2763                         __FUNCTION_NAME,
2764                         p.X, p.Y, p.Z, create_blank);
2765
2766         {
2767                 MapBlock *block = getBlockNoCreateNoEx(p);
2768                 if(block && block->isDummy() == false)
2769                         return block;
2770         }
2771
2772         {
2773                 MapBlock *block = loadBlock(p);
2774                 if(block)
2775                         return block;
2776         }
2777
2778         if (create_blank) {
2779                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
2780                 MapBlock *block = sector->createBlankBlock(p.Y);
2781
2782                 return block;
2783         }
2784
2785 #if 0
2786         if(allow_generate)
2787         {
2788                 std::map<v3s16, MapBlock*> modified_blocks;
2789                 MapBlock *block = generateBlock(p, modified_blocks);
2790                 if(block)
2791                 {
2792                         MapEditEvent event;
2793                         event.type = MEET_OTHER;
2794                         event.p = p;
2795
2796                         // Copy modified_blocks to event
2797                         for(std::map<v3s16, MapBlock*>::iterator
2798                                         i = modified_blocks.begin();
2799                                         i != modified_blocks.end(); ++i)
2800                         {
2801                                 event.modified_blocks.insert(i->first);
2802                         }
2803
2804                         // Queue event
2805                         dispatchEvent(&event);
2806
2807                         return block;
2808                 }
2809         }
2810 #endif
2811
2812         return NULL;
2813 }
2814
2815 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
2816 {
2817         MapBlock *block = getBlockNoCreateNoEx(p3d);
2818         if (block == NULL)
2819                 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
2820
2821         return block;
2822 }
2823
2824 void ServerMap::prepareBlock(MapBlock *block) {
2825 }
2826
2827 // N.B.  This requires no synchronization, since data will not be modified unless
2828 // the VoxelManipulator being updated belongs to the same thread.
2829 void ServerMap::updateVManip(v3s16 pos)
2830 {
2831         Mapgen *mg = m_emerge->getCurrentMapgen();
2832         if (!mg)
2833                 return;
2834
2835         MMVManip *vm = mg->vm;
2836         if (!vm)
2837                 return;
2838
2839         if (!vm->m_area.contains(pos))
2840                 return;
2841
2842         s32 idx = vm->m_area.index(pos);
2843         vm->m_data[idx] = getNodeNoEx(pos);
2844         vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA;
2845
2846         vm->m_is_dirty = true;
2847 }
2848
2849 s16 ServerMap::findGroundLevel(v2s16 p2d)
2850 {
2851 #if 0
2852         /*
2853                 Uh, just do something random...
2854         */
2855         // Find existing map from top to down
2856         s16 max=63;
2857         s16 min=-64;
2858         v3s16 p(p2d.X, max, p2d.Y);
2859         for(; p.Y>min; p.Y--)
2860         {
2861                 MapNode n = getNodeNoEx(p);
2862                 if(n.getContent() != CONTENT_IGNORE)
2863                         break;
2864         }
2865         if(p.Y == min)
2866                 goto plan_b;
2867         // If this node is not air, go to plan b
2868         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2869                 goto plan_b;
2870         // Search existing walkable and return it
2871         for(; p.Y>min; p.Y--)
2872         {
2873                 MapNode n = getNodeNoEx(p);
2874                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2875                         return p.Y;
2876         }
2877
2878         // Move to plan b
2879 plan_b:
2880 #endif
2881
2882         /*
2883                 Determine from map generator noise functions
2884         */
2885
2886         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
2887         return level;
2888
2889         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2890         //return (s16)level;
2891 }
2892
2893 bool ServerMap::loadFromFolders() {
2894         if(!dbase->Initialized() && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) // ?
2895                 return true;
2896         return false;
2897 }
2898
2899 void ServerMap::createDirs(std::string path)
2900 {
2901         if(fs::CreateAllDirs(path) == false)
2902         {
2903                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2904                                 <<"\""<<path<<"\""<<std::endl;
2905                 throw BaseException("ServerMap failed to create directory");
2906         }
2907 }
2908
2909 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2910 {
2911         char cc[9];
2912         switch(layout)
2913         {
2914                 case 1:
2915                         snprintf(cc, 9, "%.4x%.4x",
2916                                 (unsigned int)pos.X&0xffff,
2917                                 (unsigned int)pos.Y&0xffff);
2918
2919                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2920                 case 2:
2921                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
2922                                 (unsigned int)pos.X&0xfff,
2923                                 (unsigned int)pos.Y&0xfff);
2924
2925                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2926                 default:
2927                         assert(false);
2928                         return "";
2929         }
2930 }
2931
2932 v2s16 ServerMap::getSectorPos(std::string dirname)
2933 {
2934         unsigned int x = 0, y = 0;
2935         int r;
2936         std::string component;
2937         fs::RemoveLastPathComponent(dirname, &component, 1);
2938         if(component.size() == 8)
2939         {
2940                 // Old layout
2941                 r = sscanf(component.c_str(), "%4x%4x", &x, &y);
2942         }
2943         else if(component.size() == 3)
2944         {
2945                 // New layout
2946                 fs::RemoveLastPathComponent(dirname, &component, 2);
2947                 r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
2948                 // Sign-extend the 12 bit values up to 16 bits...
2949                 if(x&0x800) x|=0xF000;
2950                 if(y&0x800) y|=0xF000;
2951         }
2952         else
2953         {
2954                 assert(false);
2955         }
2956         assert(r == 2);
2957         v2s16 pos((s16)x, (s16)y);
2958         return pos;
2959 }
2960
2961 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2962 {
2963         v2s16 p2d = getSectorPos(sectordir);
2964
2965         if(blockfile.size() != 4){
2966                 throw InvalidFilenameException("Invalid block filename");
2967         }
2968         unsigned int y;
2969         int r = sscanf(blockfile.c_str(), "%4x", &y);
2970         if(r != 1)
2971                 throw InvalidFilenameException("Invalid block filename");
2972         return v3s16(p2d.X, y, p2d.Y);
2973 }
2974
2975 std::string ServerMap::getBlockFilename(v3s16 p)
2976 {
2977         char cc[5];
2978         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2979         return cc;
2980 }
2981
2982 void ServerMap::save(ModifiedState save_level)
2983 {
2984         DSTACK(__FUNCTION_NAME);
2985         if(m_map_saving_enabled == false)
2986         {
2987                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
2988                 return;
2989         }
2990
2991         if(save_level == MOD_STATE_CLEAN)
2992                 infostream<<"ServerMap: Saving whole map, this can take time."
2993                                 <<std::endl;
2994
2995         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
2996         {
2997                 saveMapMeta();
2998         }
2999
3000         // Profile modified reasons
3001         Profiler modprofiler;
3002
3003         u32 sector_meta_count = 0;
3004         u32 block_count = 0;
3005         u32 block_count_all = 0; // Number of blocks in memory
3006
3007         // Don't do anything with sqlite unless something is really saved
3008         bool save_started = false;
3009
3010         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
3011                 i != m_sectors.end(); ++i)
3012         {
3013                 ServerMapSector *sector = (ServerMapSector*)i->second;
3014                 assert(sector->getId() == MAPSECTOR_SERVER);
3015
3016                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
3017                 {
3018                         saveSectorMeta(sector);
3019                         sector_meta_count++;
3020                 }
3021                 std::list<MapBlock*> blocks;
3022                 sector->getBlocks(blocks);
3023
3024                 for(std::list<MapBlock*>::iterator j = blocks.begin();
3025                         j != blocks.end(); ++j)
3026                 {
3027                         MapBlock *block = *j;
3028
3029                         block_count_all++;
3030
3031                         if(block->getModified() >= (u32)save_level)
3032                         {
3033                                 // Lazy beginSave()
3034                                 if(!save_started){
3035                                         beginSave();
3036                                         save_started = true;
3037                                 }
3038
3039                                 modprofiler.add(block->getModifiedReason(), 1);
3040
3041                                 saveBlock(block);
3042                                 block_count++;
3043
3044                                 /*infostream<<"ServerMap: Written block ("
3045                                                 <<block->getPos().X<<","
3046                                                 <<block->getPos().Y<<","
3047                                                 <<block->getPos().Z<<")"
3048                                                 <<std::endl;*/
3049                         }
3050                 }
3051         }
3052         if(save_started)
3053                 endSave();
3054
3055         /*
3056                 Only print if something happened or saved whole map
3057         */
3058         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
3059                         || block_count != 0)
3060         {
3061                 infostream<<"ServerMap: Written: "
3062                                 <<sector_meta_count<<" sector metadata files, "
3063                                 <<block_count<<" block files"
3064                                 <<", "<<block_count_all<<" blocks in memory."
3065                                 <<std::endl;
3066                 PrintInfo(infostream); // ServerMap/ClientMap:
3067                 infostream<<"Blocks modified by: "<<std::endl;
3068                 modprofiler.print(infostream);
3069         }
3070 }
3071
3072 void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
3073 {
3074         if(loadFromFolders()){
3075                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
3076                                 <<"all blocks that are stored in flat files"<<std::endl;
3077         }
3078         dbase->listAllLoadableBlocks(dst);
3079 }
3080
3081 void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
3082 {
3083         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
3084                 si != m_sectors.end(); ++si)
3085         {
3086                 MapSector *sector = si->second;
3087
3088                 std::list<MapBlock*> blocks;
3089                 sector->getBlocks(blocks);
3090
3091                 for(std::list<MapBlock*>::iterator i = blocks.begin();
3092                                 i != blocks.end(); ++i)
3093                 {
3094                         MapBlock *block = (*i);
3095                         v3s16 p = block->getPos();
3096                         dst.push_back(p);
3097                 }
3098         }
3099 }
3100
3101 void ServerMap::saveMapMeta()
3102 {
3103         DSTACK(__FUNCTION_NAME);
3104
3105         /*infostream<<"ServerMap::saveMapMeta(): "
3106                         <<"seed="<<m_seed
3107                         <<std::endl;*/
3108
3109         createDirs(m_savedir);
3110
3111         std::string fullpath = m_savedir + DIR_DELIM "map_meta.txt";
3112         std::ostringstream ss(std::ios_base::binary);
3113
3114         Settings params;
3115
3116         m_emerge->saveParamsToSettings(&params);
3117         params.writeLines(ss);
3118
3119         ss<<"[end_of_params]\n";
3120
3121         if(!fs::safeWriteToFile(fullpath, ss.str()))
3122         {
3123                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
3124                                 <<"could not write "<<fullpath<<std::endl;
3125                 throw FileNotGoodException("Cannot save chunk metadata");
3126         }
3127
3128         m_map_metadata_changed = false;
3129 }
3130
3131 void ServerMap::loadMapMeta()
3132 {
3133         DSTACK(__FUNCTION_NAME);
3134
3135         Settings params;
3136         std::string fullpath = m_savedir + DIR_DELIM "map_meta.txt";
3137
3138         if (fs::PathExists(fullpath)) {
3139                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3140                 if (!is.good()) {
3141                         errorstream << "ServerMap::loadMapMeta(): "
3142                                 "could not open " << fullpath << std::endl;
3143                         throw FileNotGoodException("Cannot open map metadata");
3144                 }
3145
3146                 if (!params.parseConfigLines(is, "[end_of_params]")) {
3147                         throw SerializationError("ServerMap::loadMapMeta(): "
3148                                 "[end_of_params] not found!");
3149                 }
3150         }
3151
3152         m_emerge->loadParamsFromSettings(&params);
3153
3154         verbosestream << "ServerMap::loadMapMeta(): seed="
3155                 << m_emerge->params.seed << std::endl;
3156 }
3157
3158 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3159 {
3160         DSTACK(__FUNCTION_NAME);
3161         // Format used for writing
3162         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3163         // Get destination
3164         v2s16 pos = sector->getPos();
3165         std::string dir = getSectorDir(pos);
3166         createDirs(dir);
3167
3168         std::string fullpath = dir + DIR_DELIM + "meta";
3169         std::ostringstream ss(std::ios_base::binary);
3170
3171         sector->serialize(ss, version);
3172
3173         if(!fs::safeWriteToFile(fullpath, ss.str()))
3174                 throw FileNotGoodException("Cannot write sector metafile");
3175
3176         sector->differs_from_disk = false;
3177 }
3178
3179 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3180 {
3181         DSTACK(__FUNCTION_NAME);
3182         // Get destination
3183         v2s16 p2d = getSectorPos(sectordir);
3184
3185         ServerMapSector *sector = NULL;
3186
3187         std::string fullpath = sectordir + DIR_DELIM + "meta";
3188         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3189         if(is.good() == false)
3190         {
3191                 // If the directory exists anyway, it probably is in some old
3192                 // format. Just go ahead and create the sector.
3193                 if(fs::PathExists(sectordir))
3194                 {
3195                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3196                                         <<fullpath<<" doesn't exist but directory does."
3197                                         <<" Continuing with a sector with no metadata."
3198                                         <<std::endl;*/
3199                         sector = new ServerMapSector(this, p2d, m_gamedef);
3200                         m_sectors[p2d] = sector;
3201                 }
3202                 else
3203                 {
3204                         throw FileNotGoodException("Cannot open sector metafile");
3205                 }
3206         }
3207         else
3208         {
3209                 sector = ServerMapSector::deSerialize
3210                                 (is, this, p2d, m_sectors, m_gamedef);
3211                 if(save_after_load)
3212                         saveSectorMeta(sector);
3213         }
3214
3215         sector->differs_from_disk = false;
3216
3217         return sector;
3218 }
3219
3220 bool ServerMap::loadSectorMeta(v2s16 p2d)
3221 {
3222         DSTACK(__FUNCTION_NAME);
3223
3224         // The directory layout we're going to load from.
3225         //  1 - original sectors/xxxxzzzz/
3226         //  2 - new sectors2/xxx/zzz/
3227         //  If we load from anything but the latest structure, we will
3228         //  immediately save to the new one, and remove the old.
3229         int loadlayout = 1;
3230         std::string sectordir1 = getSectorDir(p2d, 1);
3231         std::string sectordir;
3232         if(fs::PathExists(sectordir1))
3233         {
3234                 sectordir = sectordir1;
3235         }
3236         else
3237         {
3238                 loadlayout = 2;
3239                 sectordir = getSectorDir(p2d, 2);
3240         }
3241
3242         try{
3243                 loadSectorMeta(sectordir, loadlayout != 2);
3244         }
3245         catch(InvalidFilenameException &e)
3246         {
3247                 return false;
3248         }
3249         catch(FileNotGoodException &e)
3250         {
3251                 return false;
3252         }
3253         catch(std::exception &e)
3254         {
3255                 return false;
3256         }
3257
3258         return true;
3259 }
3260
3261 #if 0
3262 bool ServerMap::loadSectorFull(v2s16 p2d)
3263 {
3264         DSTACK(__FUNCTION_NAME);
3265
3266         MapSector *sector = NULL;
3267
3268         // The directory layout we're going to load from.
3269         //  1 - original sectors/xxxxzzzz/
3270         //  2 - new sectors2/xxx/zzz/
3271         //  If we load from anything but the latest structure, we will
3272         //  immediately save to the new one, and remove the old.
3273         int loadlayout = 1;
3274         std::string sectordir1 = getSectorDir(p2d, 1);
3275         std::string sectordir;
3276         if(fs::PathExists(sectordir1))
3277         {
3278                 sectordir = sectordir1;
3279         }
3280         else
3281         {
3282                 loadlayout = 2;
3283                 sectordir = getSectorDir(p2d, 2);
3284         }
3285
3286         try{
3287                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3288         }
3289         catch(InvalidFilenameException &e)
3290         {
3291                 return false;
3292         }
3293         catch(FileNotGoodException &e)
3294         {
3295                 return false;
3296         }
3297         catch(std::exception &e)
3298         {
3299                 return false;
3300         }
3301
3302         /*
3303                 Load blocks
3304         */
3305         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3306                         (sectordir);
3307         std::vector<fs::DirListNode>::iterator i2;
3308         for(i2=list2.begin(); i2!=list2.end(); i2++)
3309         {
3310                 // We want files
3311                 if(i2->dir)
3312                         continue;
3313                 try{
3314                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3315                 }
3316                 catch(InvalidFilenameException &e)
3317                 {
3318                         // This catches unknown crap in directory
3319                 }
3320         }
3321
3322         if(loadlayout != 2)
3323         {
3324                 infostream<<"Sector converted to new layout - deleting "<<
3325                         sectordir1<<std::endl;
3326                 fs::RecursiveDelete(sectordir1);
3327         }
3328
3329         return true;
3330 }
3331 #endif
3332
3333 void ServerMap::beginSave()
3334 {
3335         dbase->beginSave();
3336 }
3337
3338 void ServerMap::endSave()
3339 {
3340         dbase->endSave();
3341 }
3342
3343 bool ServerMap::saveBlock(MapBlock *block)
3344 {
3345         return saveBlock(block, dbase);
3346 }
3347
3348 bool ServerMap::saveBlock(MapBlock *block, Database *db)
3349 {
3350         v3s16 p3d = block->getPos();
3351
3352         // Dummy blocks are not written
3353         if (block->isDummy()) {
3354                 errorstream << "WARNING: saveBlock: Not writing dummy block "
3355                         << PP(p3d) << std::endl;
3356                 return true;
3357         }
3358
3359         // Format used for writing
3360         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3361
3362         /*
3363                 [0] u8 serialization version
3364                 [1] data
3365         */
3366         std::ostringstream o(std::ios_base::binary);
3367         o.write((char*) &version, 1);
3368         block->serialize(o, version, true);
3369
3370         std::string data = o.str();
3371         bool ret = db->saveBlock(p3d, data);
3372         if(ret) {
3373                 // We just wrote it to the disk so clear modified flag
3374                 block->resetModified();
3375         }
3376         return ret;
3377 }
3378
3379 void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
3380                 MapSector *sector, bool save_after_load)
3381 {
3382         DSTACK(__FUNCTION_NAME);
3383
3384         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3385         try {
3386
3387                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3388                 if(is.good() == false)
3389                         throw FileNotGoodException("Cannot open block file");
3390
3391                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3392                 v2s16 p2d(p3d.X, p3d.Z);
3393
3394                 assert(sector->getPos() == p2d);
3395
3396                 u8 version = SER_FMT_VER_INVALID;
3397                 is.read((char*)&version, 1);
3398
3399                 if(is.fail())
3400                         throw SerializationError("ServerMap::loadBlock(): Failed"
3401                                         " to read MapBlock version");
3402
3403                 /*u32 block_size = MapBlock::serializedLength(version);
3404                 SharedBuffer<u8> data(block_size);
3405                 is.read((char*)*data, block_size);*/
3406
3407                 // This will always return a sector because we're the server
3408                 //MapSector *sector = emergeSector(p2d);
3409
3410                 MapBlock *block = NULL;
3411                 bool created_new = false;
3412                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3413                 if(block == NULL)
3414                 {
3415                         block = sector->createBlankBlockNoInsert(p3d.Y);
3416                         created_new = true;
3417                 }
3418
3419                 // Read basic data
3420                 block->deSerialize(is, version, true);
3421
3422                 // If it's a new block, insert it to the map
3423                 if(created_new)
3424                         sector->insertBlock(block);
3425
3426                 /*
3427                         Save blocks loaded in old format in new format
3428                 */
3429
3430                 if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
3431                 {
3432                         saveBlock(block);
3433
3434                         // Should be in database now, so delete the old file
3435                         fs::RecursiveDelete(fullpath);
3436                 }
3437
3438                 // We just loaded it from the disk, so it's up-to-date.
3439                 block->resetModified();
3440
3441         }
3442         catch(SerializationError &e)
3443         {
3444                 infostream<<"WARNING: Invalid block data on disk "
3445                                 <<"fullpath="<<fullpath
3446                                 <<" (SerializationError). "
3447                                 <<"what()="<<e.what()
3448                                 <<std::endl;
3449                                 // Ignoring. A new one will be generated.
3450                 assert(0);
3451
3452                 // TODO: Backup file; name is in fullpath.
3453         }
3454 }
3455
3456 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3457 {
3458         DSTACK(__FUNCTION_NAME);
3459
3460         try {
3461                 std::istringstream is(*blob, std::ios_base::binary);
3462
3463                 u8 version = SER_FMT_VER_INVALID;
3464                 is.read((char*)&version, 1);
3465
3466                 if(is.fail())
3467                         throw SerializationError("ServerMap::loadBlock(): Failed"
3468                                         " to read MapBlock version");
3469
3470                 /*u32 block_size = MapBlock::serializedLength(version);
3471                 SharedBuffer<u8> data(block_size);
3472                 is.read((char*)*data, block_size);*/
3473
3474                 // This will always return a sector because we're the server
3475                 //MapSector *sector = emergeSector(p2d);
3476
3477                 MapBlock *block = NULL;
3478                 bool created_new = false;
3479                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3480                 if(block == NULL)
3481                 {
3482                         block = sector->createBlankBlockNoInsert(p3d.Y);
3483                         created_new = true;
3484                 }
3485
3486                 // Read basic data
3487                 block->deSerialize(is, version, true);
3488
3489                 // If it's a new block, insert it to the map
3490                 if(created_new)
3491                         sector->insertBlock(block);
3492
3493                 /*
3494                         Save blocks loaded in old format in new format
3495                 */
3496
3497                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
3498                 // Only save if asked to; no need to update version
3499                 if(save_after_load)
3500                         saveBlock(block);
3501
3502                 // We just loaded it from, so it's up-to-date.
3503                 block->resetModified();
3504
3505         }
3506         catch(SerializationError &e)
3507         {
3508                 errorstream<<"Invalid block data in database"
3509                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3510                                 <<" (SerializationError): "<<e.what()<<std::endl;
3511
3512                 // TODO: Block should be marked as invalid in memory so that it is
3513                 // not touched but the game can run
3514
3515                 if(g_settings->getBool("ignore_world_load_errors")){
3516                         errorstream<<"Ignoring block load error. Duck and cover! "
3517                                         <<"(ignore_world_load_errors)"<<std::endl;
3518                 } else {
3519                         throw SerializationError("Invalid block data in database");
3520                         //assert(0);
3521                 }
3522         }
3523 }
3524
3525 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3526 {
3527         DSTACK(__FUNCTION_NAME);
3528
3529         v2s16 p2d(blockpos.X, blockpos.Z);
3530
3531         std::string ret;
3532
3533         ret = dbase->loadBlock(blockpos);
3534         if (ret != "") {
3535                 loadBlock(&ret, blockpos, createSector(p2d), false);
3536                 return getBlockNoCreateNoEx(blockpos);
3537         }
3538         // Not found in database, try the files
3539
3540         // The directory layout we're going to load from.
3541         //  1 - original sectors/xxxxzzzz/
3542         //  2 - new sectors2/xxx/zzz/
3543         //  If we load from anything but the latest structure, we will
3544         //  immediately save to the new one, and remove the old.
3545         int loadlayout = 1;
3546         std::string sectordir1 = getSectorDir(p2d, 1);
3547         std::string sectordir;
3548         if(fs::PathExists(sectordir1))
3549         {
3550                 sectordir = sectordir1;
3551         }
3552         else
3553         {
3554                 loadlayout = 2;
3555                 sectordir = getSectorDir(p2d, 2);
3556         }
3557
3558         /*
3559                 Make sure sector is loaded
3560         */
3561         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3562         if(sector == NULL)
3563         {
3564                 try{
3565                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3566                 }
3567                 catch(InvalidFilenameException &e)
3568                 {
3569                         return NULL;
3570                 }
3571                 catch(FileNotGoodException &e)
3572                 {
3573                         return NULL;
3574                 }
3575                 catch(std::exception &e)
3576                 {
3577                         return NULL;
3578                 }
3579         }
3580
3581         /*
3582                 Make sure file exists
3583         */
3584
3585         std::string blockfilename = getBlockFilename(blockpos);
3586         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3587                 return NULL;
3588
3589         /*
3590                 Load block and save it to the database
3591         */
3592         loadBlock(sectordir, blockfilename, sector, true);
3593         return getBlockNoCreateNoEx(blockpos);
3594 }
3595
3596 bool ServerMap::deleteBlock(v3s16 blockpos)
3597 {
3598         if (!dbase->deleteBlock(blockpos))
3599                 return false;
3600
3601         MapBlock *block = getBlockNoCreateNoEx(blockpos);
3602         if (block) {
3603                 v2s16 p2d(blockpos.X, blockpos.Z);
3604                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
3605                 if (!sector)
3606                         return false;
3607                 sector->deleteBlock(block);
3608         }
3609
3610         return true;
3611 }
3612
3613 void ServerMap::PrintInfo(std::ostream &out)
3614 {
3615         out<<"ServerMap: ";
3616 }
3617
3618 MMVManip::MMVManip(Map *map):
3619                 VoxelManipulator(),
3620                 m_is_dirty(false),
3621                 m_create_area(false),
3622                 m_map(map)
3623 {
3624 }
3625
3626 MMVManip::~MMVManip()
3627 {
3628 }
3629
3630 void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
3631         bool load_if_inexistent)
3632 {
3633         TimeTaker timer1("initialEmerge", &emerge_time);
3634
3635         // Units of these are MapBlocks
3636         v3s16 p_min = blockpos_min;
3637         v3s16 p_max = blockpos_max;
3638
3639         VoxelArea block_area_nodes
3640                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3641
3642         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
3643         if(size_MB >= 1)
3644         {
3645                 infostream<<"initialEmerge: area: ";
3646                 block_area_nodes.print(infostream);
3647                 infostream<<" ("<<size_MB<<"MB)";
3648                 infostream<<std::endl;
3649         }
3650
3651         addArea(block_area_nodes);
3652
3653         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3654         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3655         for(s32 x=p_min.X; x<=p_max.X; x++)
3656         {
3657                 u8 flags = 0;
3658                 MapBlock *block;
3659                 v3s16 p(x,y,z);
3660                 std::map<v3s16, u8>::iterator n;
3661                 n = m_loaded_blocks.find(p);
3662                 if(n != m_loaded_blocks.end())
3663                         continue;
3664
3665                 bool block_data_inexistent = false;
3666                 try
3667                 {
3668                         TimeTaker timer1("emerge load", &emerge_load_time);
3669
3670                         block = m_map->getBlockNoCreate(p);
3671                         if(block->isDummy())
3672                                 block_data_inexistent = true;
3673                         else
3674                                 block->copyTo(*this);
3675                 }
3676                 catch(InvalidPositionException &e)
3677                 {
3678                         block_data_inexistent = true;
3679                 }
3680
3681                 if(block_data_inexistent)
3682                 {
3683
3684                         if (load_if_inexistent) {
3685                                 ServerMap *svrmap = (ServerMap *)m_map;
3686                                 block = svrmap->emergeBlock(p, false);
3687                                 if (block == NULL)
3688                                         block = svrmap->createBlock(p);
3689                                 block->copyTo(*this);
3690                         } else {
3691                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
3692
3693                                 /*
3694                                         Mark area inexistent
3695                                 */
3696                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3697                                 // Fill with VOXELFLAG_NO_DATA
3698                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3699                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3700                                 {
3701                                         s32 i = m_area.index(a.MinEdge.X,y,z);
3702                                         memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
3703                                 }
3704                         }
3705                 }
3706                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
3707                 {
3708                         // Mark that block was loaded as blank
3709                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
3710                 }*/
3711
3712                 m_loaded_blocks[p] = flags;
3713         }
3714
3715         m_is_dirty = false;
3716 }
3717
3718 void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
3719         bool overwrite_generated)
3720 {
3721         if(m_area.getExtent() == v3s16(0,0,0))
3722                 return;
3723
3724         /*
3725                 Copy data of all blocks
3726         */
3727         for(std::map<v3s16, u8>::iterator
3728                         i = m_loaded_blocks.begin();
3729                         i != m_loaded_blocks.end(); ++i)
3730         {
3731                 v3s16 p = i->first;
3732                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
3733                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
3734                 if ((existed == false) || (block == NULL) ||
3735                         (overwrite_generated == false && block->isGenerated() == true))
3736                         continue;
3737
3738                 block->copyFrom(*this);
3739
3740                 if(modified_blocks)
3741                         (*modified_blocks)[p] = block;
3742         }
3743 }
3744
3745 //END