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