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