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