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