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