]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
Liquids: Preserve flow state if 'ignore' is a neighbour
[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 = getBlockNoCreateNoEx(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                 bool ignored_sources = false;
1313                 for (u16 i = 0; i < 6; i++) {
1314                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1315                         switch (i) {
1316                                 case 1:
1317                                         nt = NEIGHBOR_UPPER;
1318                                         break;
1319                                 case 4:
1320                                         nt = NEIGHBOR_LOWER;
1321                                         break;
1322                         }
1323                         v3s16 npos = p0 + dirs[i];
1324                         NodeNeighbor nb(getNodeNoEx(npos), nt, npos);
1325                         const ContentFeatures &cfnb = nodemgr->get(nb.n);
1326                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
1327                                 case LIQUID_NONE:
1328                                         if (cfnb.floodable) {
1329                                                 airs[num_airs++] = nb;
1330                                                 // if the current node is a water source the neighbor
1331                                                 // should be enqueded for transformation regardless of whether the
1332                                                 // current node changes or not.
1333                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
1334                                                         m_transforming_liquid.push_back(npos);
1335                                                 // if the current node happens to be a flowing node, it will start to flow down here.
1336                                                 if (nb.t == NEIGHBOR_LOWER)
1337                                                         flowing_down = true;
1338                                         } else {
1339                                                 neutrals[num_neutrals++] = nb;
1340                                                 if (nb.n.getContent() == CONTENT_IGNORE) {
1341                                                         // If node below is ignore prevent water from
1342                                                         // spreading outwards and otherwise prevent from
1343                                                         // flowing away as ignore node might be the source
1344                                                         if (nb.t == NEIGHBOR_LOWER)
1345                                                                 flowing_down = true;
1346                                                         else
1347                                                                 ignored_sources = true;
1348                                                 }
1349                                         }
1350                                         break;
1351                                 case LIQUID_SOURCE:
1352                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1353                                         if (liquid_kind == CONTENT_AIR)
1354                                                 liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing);
1355                                         if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
1356                                                 neutrals[num_neutrals++] = nb;
1357                                         } else {
1358                                                 // Do not count bottom source, it will screw things up
1359                                                 if(dirs[i].Y != -1)
1360                                                         sources[num_sources++] = nb;
1361                                         }
1362                                         break;
1363                                 case LIQUID_FLOWING:
1364                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1365                                         if (liquid_kind == CONTENT_AIR)
1366                                                 liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing);
1367                                         if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
1368                                                 neutrals[num_neutrals++] = nb;
1369                                         } else {
1370                                                 flows[num_flows++] = nb;
1371                                                 if (nb.t == NEIGHBOR_LOWER)
1372                                                         flowing_down = true;
1373                                         }
1374                                         break;
1375                         }
1376                 }
1377
1378                 /*
1379                         decide on the type (and possibly level) of the current node
1380                  */
1381                 content_t new_node_content;
1382                 s8 new_node_level = -1;
1383                 s8 max_node_level = -1;
1384
1385                 u8 range = nodemgr->get(liquid_kind).liquid_range;
1386                 if (range > LIQUID_LEVEL_MAX + 1)
1387                         range = LIQUID_LEVEL_MAX + 1;
1388
1389                 if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
1390                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1391                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1392                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1393                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
1394                 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
1395                         // liquid_kind is set properly, see above
1396                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
1397                         if (new_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
1398                                 new_node_content = liquid_kind;
1399                         else
1400                                 new_node_content = floodable_node;
1401                 } else if (ignored_sources && liquid_level >= 0) {
1402                         // Maybe there are neighbouring sources that aren't loaded yet
1403                         // so prevent flowing away.
1404                         new_node_level = liquid_level;
1405                         new_node_content = liquid_kind;
1406                 } else {
1407                         // no surrounding sources, so get the maximum level that can flow into this node
1408                         for (u16 i = 0; i < num_flows; i++) {
1409                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1410                                 switch (flows[i].t) {
1411                                         case NEIGHBOR_UPPER:
1412                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
1413                                                         max_node_level = LIQUID_LEVEL_MAX;
1414                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1415                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
1416                                                 } else if (nb_liquid_level > max_node_level) {
1417                                                         max_node_level = nb_liquid_level;
1418                                                 }
1419                                                 break;
1420                                         case NEIGHBOR_LOWER:
1421                                                 break;
1422                                         case NEIGHBOR_SAME_LEVEL:
1423                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1424                                                                 nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level)
1425                                                         max_node_level = nb_liquid_level - 1;
1426                                                 break;
1427                                 }
1428                         }
1429
1430                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
1431                         if (viscosity > 1 && max_node_level != liquid_level) {
1432                                 // amount to gain, limited by viscosity
1433                                 // must be at least 1 in absolute value
1434                                 s8 level_inc = max_node_level - liquid_level;
1435                                 if (level_inc < -viscosity || level_inc > viscosity)
1436                                         new_node_level = liquid_level + level_inc/viscosity;
1437                                 else if (level_inc < 0)
1438                                         new_node_level = liquid_level - 1;
1439                                 else if (level_inc > 0)
1440                                         new_node_level = liquid_level + 1;
1441                                 if (new_node_level != max_node_level)
1442                                         must_reflow.push_back(p0);
1443                         } else {
1444                                 new_node_level = max_node_level;
1445                         }
1446
1447                         if (max_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
1448                                 new_node_content = liquid_kind;
1449                         else
1450                                 new_node_content = floodable_node;
1451
1452                 }
1453
1454                 /*
1455                         check if anything has changed. if not, just continue with the next node.
1456                  */
1457                 if (new_node_content == n0.getContent() &&
1458                                 (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1459                                 ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1460                                 ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1461                                 == flowing_down)))
1462                         continue;
1463
1464
1465                 /*
1466                         update the current node
1467                  */
1468                 MapNode n00 = n0;
1469                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1470                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
1471                         // set level to last 3 bits, flowing down bit to 4th bit
1472                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1473                 } else {
1474                         // set the liquid level and flow bit to 0
1475                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1476                 }
1477                 n0.setContent(new_node_content);
1478
1479                 // Ignore light (because calling voxalgo::update_lighting_nodes)
1480                 n0.setLight(LIGHTBANK_DAY, 0, nodemgr);
1481                 n0.setLight(LIGHTBANK_NIGHT, 0, nodemgr);
1482
1483                 // Find out whether there is a suspect for this action
1484                 std::string suspect;
1485                 if (m_gamedef->rollback())
1486                         suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
1487
1488                 if (m_gamedef->rollback() && !suspect.empty()) {
1489                         // Blame suspect
1490                         RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
1491                         // Get old node for rollback
1492                         RollbackNode rollback_oldnode(this, p0, m_gamedef);
1493                         // Set node
1494                         setNode(p0, n0);
1495                         // Report
1496                         RollbackNode rollback_newnode(this, p0, m_gamedef);
1497                         RollbackAction action;
1498                         action.setSetNode(p0, rollback_oldnode, rollback_newnode);
1499                         m_gamedef->rollback()->reportAction(action);
1500                 } else {
1501                         // Set node
1502                         setNode(p0, n0);
1503                 }
1504
1505                 v3s16 blockpos = getNodeBlockPos(p0);
1506                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1507                 if (block != NULL) {
1508                         modified_blocks[blockpos] =  block;
1509                         changed_nodes.push_back(std::pair<v3s16, MapNode>(p0, n00));
1510                 }
1511
1512                 /*
1513                         enqueue neighbors for update if neccessary
1514                  */
1515                 switch (nodemgr->get(n0.getContent()).liquid_type) {
1516                         case LIQUID_SOURCE:
1517                         case LIQUID_FLOWING:
1518                                 // make sure source flows into all neighboring nodes
1519                                 for (u16 i = 0; i < num_flows; i++)
1520                                         if (flows[i].t != NEIGHBOR_UPPER)
1521                                                 m_transforming_liquid.push_back(flows[i].p);
1522                                 for (u16 i = 0; i < num_airs; i++)
1523                                         if (airs[i].t != NEIGHBOR_UPPER)
1524                                                 m_transforming_liquid.push_back(airs[i].p);
1525                                 break;
1526                         case LIQUID_NONE:
1527                                 // this flow has turned to air; neighboring flows might need to do the same
1528                                 for (u16 i = 0; i < num_flows; i++)
1529                                         m_transforming_liquid.push_back(flows[i].p);
1530                                 break;
1531                 }
1532         }
1533         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1534
1535         for (std::deque<v3s16>::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter)
1536                 m_transforming_liquid.push_back(*iter);
1537
1538         voxalgo::update_lighting_nodes(this, nodemgr, changed_nodes, modified_blocks);
1539
1540
1541         /* ----------------------------------------------------------------------
1542          * Manage the queue so that it does not grow indefinately
1543          */
1544         u16 time_until_purge = g_settings->getU16("liquid_queue_purge_time");
1545
1546         if (time_until_purge == 0)
1547                 return; // Feature disabled
1548
1549         time_until_purge *= 1000;       // seconds -> milliseconds
1550
1551         u32 curr_time = getTime(PRECISION_MILLI);
1552         u32 prev_unprocessed = m_unprocessed_count;
1553         m_unprocessed_count = m_transforming_liquid.size();
1554
1555         // if unprocessed block count is decreasing or stable
1556         if (m_unprocessed_count <= prev_unprocessed) {
1557                 m_queue_size_timer_started = false;
1558         } else {
1559                 if (!m_queue_size_timer_started)
1560                         m_inc_trending_up_start_time = curr_time;
1561                 m_queue_size_timer_started = true;
1562         }
1563
1564         // Account for curr_time overflowing
1565         if (m_queue_size_timer_started && m_inc_trending_up_start_time > curr_time)
1566                 m_queue_size_timer_started = false;
1567
1568         /* If the queue has been growing for more than liquid_queue_purge_time seconds
1569          * and the number of unprocessed blocks is still > liquid_loop_max then we
1570          * cannot keep up; dump the oldest blocks from the queue so that the queue
1571          * has liquid_loop_max items in it
1572          */
1573         if (m_queue_size_timer_started
1574                         && curr_time - m_inc_trending_up_start_time > time_until_purge
1575                         && m_unprocessed_count > liquid_loop_max) {
1576
1577                 size_t dump_qty = m_unprocessed_count - liquid_loop_max;
1578
1579                 infostream << "transformLiquids(): DUMPING " << dump_qty
1580                            << " blocks from the queue" << std::endl;
1581
1582                 while (dump_qty--)
1583                         m_transforming_liquid.pop_front();
1584
1585                 m_queue_size_timer_started = false; // optimistically assume we can keep up now
1586                 m_unprocessed_count = m_transforming_liquid.size();
1587         }
1588 }
1589
1590 std::vector<v3s16> Map::findNodesWithMetadata(v3s16 p1, v3s16 p2)
1591 {
1592         std::vector<v3s16> positions_with_meta;
1593
1594         sortBoxVerticies(p1, p2);
1595         v3s16 bpmin = getNodeBlockPos(p1);
1596         v3s16 bpmax = getNodeBlockPos(p2);
1597
1598         VoxelArea area(p1, p2);
1599
1600         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
1601         for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
1602         for (s16 x = bpmin.X; x <= bpmax.X; x++) {
1603                 v3s16 blockpos(x, y, z);
1604
1605                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1606                 if (!block) {
1607                         verbosestream << "Map::getNodeMetadata(): Need to emerge "
1608                                 << PP(blockpos) << std::endl;
1609                         block = emergeBlock(blockpos, false);
1610                 }
1611                 if (!block) {
1612                         infostream << "WARNING: Map::getNodeMetadata(): Block not found"
1613                                 << std::endl;
1614                         continue;
1615                 }
1616
1617                 v3s16 p_base = blockpos * MAP_BLOCKSIZE;
1618                 std::vector<v3s16> keys = block->m_node_metadata.getAllKeys();
1619                 for (size_t i = 0; i != keys.size(); i++) {
1620                         v3s16 p(keys[i] + p_base);
1621                         if (!area.contains(p))
1622                                 continue;
1623
1624                         positions_with_meta.push_back(p);
1625                 }
1626         }
1627
1628         return positions_with_meta;
1629 }
1630
1631 NodeMetadata *Map::getNodeMetadata(v3s16 p)
1632 {
1633         v3s16 blockpos = getNodeBlockPos(p);
1634         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1635         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1636         if(!block){
1637                 infostream<<"Map::getNodeMetadata(): Need to emerge "
1638                                 <<PP(blockpos)<<std::endl;
1639                 block = emergeBlock(blockpos, false);
1640         }
1641         if(!block){
1642                 warningstream<<"Map::getNodeMetadata(): Block not found"
1643                                 <<std::endl;
1644                 return NULL;
1645         }
1646         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1647         return meta;
1648 }
1649
1650 bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1651 {
1652         v3s16 blockpos = getNodeBlockPos(p);
1653         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1654         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1655         if(!block){
1656                 infostream<<"Map::setNodeMetadata(): Need to emerge "
1657                                 <<PP(blockpos)<<std::endl;
1658                 block = emergeBlock(blockpos, false);
1659         }
1660         if(!block){
1661                 warningstream<<"Map::setNodeMetadata(): Block not found"
1662                                 <<std::endl;
1663                 return false;
1664         }
1665         block->m_node_metadata.set(p_rel, meta);
1666         return true;
1667 }
1668
1669 void Map::removeNodeMetadata(v3s16 p)
1670 {
1671         v3s16 blockpos = getNodeBlockPos(p);
1672         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1673         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1674         if(block == NULL)
1675         {
1676                 warningstream<<"Map::removeNodeMetadata(): Block not found"
1677                                 <<std::endl;
1678                 return;
1679         }
1680         block->m_node_metadata.remove(p_rel);
1681 }
1682
1683 NodeTimer Map::getNodeTimer(v3s16 p)
1684 {
1685         v3s16 blockpos = getNodeBlockPos(p);
1686         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1687         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1688         if(!block){
1689                 infostream<<"Map::getNodeTimer(): Need to emerge "
1690                                 <<PP(blockpos)<<std::endl;
1691                 block = emergeBlock(blockpos, false);
1692         }
1693         if(!block){
1694                 warningstream<<"Map::getNodeTimer(): Block not found"
1695                                 <<std::endl;
1696                 return NodeTimer();
1697         }
1698         NodeTimer t = block->m_node_timers.get(p_rel);
1699         NodeTimer nt(t.timeout, t.elapsed, p);
1700         return nt;
1701 }
1702
1703 void Map::setNodeTimer(const NodeTimer &t)
1704 {
1705         v3s16 p = t.position;
1706         v3s16 blockpos = getNodeBlockPos(p);
1707         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1708         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1709         if(!block){
1710                 infostream<<"Map::setNodeTimer(): Need to emerge "
1711                                 <<PP(blockpos)<<std::endl;
1712                 block = emergeBlock(blockpos, false);
1713         }
1714         if(!block){
1715                 warningstream<<"Map::setNodeTimer(): Block not found"
1716                                 <<std::endl;
1717                 return;
1718         }
1719         NodeTimer nt(t.timeout, t.elapsed, p_rel);
1720         block->m_node_timers.set(nt);
1721 }
1722
1723 void Map::removeNodeTimer(v3s16 p)
1724 {
1725         v3s16 blockpos = getNodeBlockPos(p);
1726         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1727         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1728         if(block == NULL)
1729         {
1730                 warningstream<<"Map::removeNodeTimer(): Block not found"
1731                                 <<std::endl;
1732                 return;
1733         }
1734         block->m_node_timers.remove(p_rel);
1735 }
1736
1737 /*
1738         ServerMap
1739 */
1740 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
1741         Map(dout_server, gamedef),
1742         settings_mgr(g_settings, savedir + DIR_DELIM + "map_meta.txt"),
1743         m_emerge(emerge),
1744         m_map_metadata_changed(true)
1745 {
1746         verbosestream<<FUNCTION_NAME<<std::endl;
1747
1748         // Tell the EmergeManager about our MapSettingsManager
1749         emerge->map_settings_mgr = &settings_mgr;
1750
1751         /*
1752                 Try to load map; if not found, create a new one.
1753         */
1754
1755         // Determine which database backend to use
1756         std::string conf_path = savedir + DIR_DELIM + "world.mt";
1757         Settings conf;
1758         bool succeeded = conf.readConfigFile(conf_path.c_str());
1759         if (!succeeded || !conf.exists("backend")) {
1760                 // fall back to sqlite3
1761                 conf.set("backend", "sqlite3");
1762         }
1763         std::string backend = conf.get("backend");
1764         dbase = createDatabase(backend, savedir, conf);
1765
1766         if (!conf.updateConfigFile(conf_path.c_str()))
1767                 errorstream << "ServerMap::ServerMap(): Failed to update world.mt!" << std::endl;
1768
1769         m_savedir = savedir;
1770         m_map_saving_enabled = false;
1771
1772         try
1773         {
1774                 // If directory exists, check contents and load if possible
1775                 if(fs::PathExists(m_savedir))
1776                 {
1777                         // If directory is empty, it is safe to save into it.
1778                         if(fs::GetDirListing(m_savedir).size() == 0)
1779                         {
1780                                 infostream<<"ServerMap: Empty save directory is valid."
1781                                                 <<std::endl;
1782                                 m_map_saving_enabled = true;
1783                         }
1784                         else
1785                         {
1786
1787                                 if (settings_mgr.loadMapMeta()) {
1788                                         infostream << "ServerMap: Metadata loaded from "
1789                                                 << savedir << std::endl;
1790                                 } else {
1791                                         infostream << "ServerMap: Metadata could not be loaded "
1792                                                 "from " << savedir << ", assuming valid save "
1793                                                 "directory." << std::endl;
1794                                 }
1795
1796                                 m_map_saving_enabled = true;
1797                                 // Map loaded, not creating new one
1798                                 return;
1799                         }
1800                 }
1801                 // If directory doesn't exist, it is safe to save to it
1802                 else{
1803                         m_map_saving_enabled = true;
1804                 }
1805         }
1806         catch(std::exception &e)
1807         {
1808                 warningstream<<"ServerMap: Failed to load map from "<<savedir
1809                                 <<", exception: "<<e.what()<<std::endl;
1810                 infostream<<"Please remove the map or fix it."<<std::endl;
1811                 warningstream<<"Map saving will be disabled."<<std::endl;
1812         }
1813
1814         infostream<<"Initializing new map."<<std::endl;
1815
1816         // Create zero sector
1817         emergeSector(v2s16(0,0));
1818
1819         // Initially write whole map
1820         save(MOD_STATE_CLEAN);
1821 }
1822
1823 ServerMap::~ServerMap()
1824 {
1825         verbosestream<<FUNCTION_NAME<<std::endl;
1826
1827         try
1828         {
1829                 if(m_map_saving_enabled)
1830                 {
1831                         // Save only changed parts
1832                         save(MOD_STATE_WRITE_AT_UNLOAD);
1833                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
1834                 }
1835                 else
1836                 {
1837                         infostream<<"ServerMap: Map not saved"<<std::endl;
1838                 }
1839         }
1840         catch(std::exception &e)
1841         {
1842                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
1843                                 <<", exception: "<<e.what()<<std::endl;
1844         }
1845
1846         /*
1847                 Close database if it was opened
1848         */
1849         delete dbase;
1850
1851 #if 0
1852         /*
1853                 Free all MapChunks
1854         */
1855         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1856         for(; i.atEnd() == false; i++)
1857         {
1858                 MapChunk *chunk = i.getNode()->getValue();
1859                 delete chunk;
1860         }
1861 #endif
1862 }
1863
1864 MapgenParams *ServerMap::getMapgenParams()
1865 {
1866         // getMapgenParams() should only ever be called after Server is initialized
1867         assert(settings_mgr.mapgen_params != NULL);
1868         return settings_mgr.mapgen_params;
1869 }
1870
1871 u64 ServerMap::getSeed()
1872 {
1873         return getMapgenParams()->seed;
1874 }
1875
1876 s16 ServerMap::getWaterLevel()
1877 {
1878         return getMapgenParams()->water_level;
1879 }
1880
1881 bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
1882 {
1883         s16 csize = getMapgenParams()->chunksize;
1884         v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
1885         v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
1886
1887         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1888         EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax));
1889
1890         v3s16 extra_borders(1, 1, 1);
1891         v3s16 full_bpmin = bpmin - extra_borders;
1892         v3s16 full_bpmax = bpmax + extra_borders;
1893
1894         // Do nothing if not inside limits (+-1 because of neighbors)
1895         if (blockpos_over_limit(full_bpmin) ||
1896                 blockpos_over_limit(full_bpmax))
1897                 return false;
1898
1899         data->seed = getSeed();
1900         data->blockpos_min = bpmin;
1901         data->blockpos_max = bpmax;
1902         data->blockpos_requested = blockpos;
1903         data->nodedef = m_gamedef->ndef();
1904
1905         /*
1906                 Create the whole area of this and the neighboring blocks
1907         */
1908         for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
1909         for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) {
1910                 v2s16 sectorpos(x, z);
1911                 // Sector metadata is loaded from disk if not already loaded.
1912                 ServerMapSector *sector = createSector(sectorpos);
1913                 FATAL_ERROR_IF(sector == NULL, "createSector() failed");
1914
1915                 for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
1916                         v3s16 p(x, y, z);
1917
1918                         MapBlock *block = emergeBlock(p, false);
1919                         if (block == NULL) {
1920                                 block = createBlock(p);
1921
1922                                 // Block gets sunlight if this is true.
1923                                 // Refer to the map generator heuristics.
1924                                 bool ug = m_emerge->isBlockUnderground(p);
1925                                 block->setIsUnderground(ug);
1926                         }
1927                 }
1928         }
1929
1930         /*
1931                 Now we have a big empty area.
1932
1933                 Make a ManualMapVoxelManipulator that contains this and the
1934                 neighboring blocks
1935         */
1936
1937         data->vmanip = new MMVManip(this);
1938         data->vmanip->initialEmerge(full_bpmin, full_bpmax);
1939
1940         // Note: we may need this again at some point.
1941 #if 0
1942         // Ensure none of the blocks to be generated were marked as
1943         // containing CONTENT_IGNORE
1944         for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
1945                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
1946                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
1947                                 core::map<v3s16, u8>::Node *n;
1948                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
1949                                 if (n == NULL)
1950                                         continue;
1951                                 u8 flags = n->getValue();
1952                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
1953                                 n->setValue(flags);
1954                         }
1955                 }
1956         }
1957 #endif
1958
1959         // Data is ready now.
1960         return true;
1961 }
1962
1963 void ServerMap::finishBlockMake(BlockMakeData *data,
1964         std::map<v3s16, MapBlock*> *changed_blocks)
1965 {
1966         v3s16 bpmin = data->blockpos_min;
1967         v3s16 bpmax = data->blockpos_max;
1968
1969         v3s16 extra_borders(1, 1, 1);
1970         v3s16 full_bpmin = bpmin - extra_borders;
1971         v3s16 full_bpmax = bpmax + extra_borders;
1972
1973         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
1974         EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
1975
1976         /*
1977                 Set lighting to non-expired state in all of them.
1978                 This is cheating, but it is not fast enough if all of them
1979                 would actually be updated.
1980         */
1981         for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
1982         for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++)
1983         for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
1984                 MapBlock *block = emergeBlock(v3s16(x, y, z), false);
1985                 if (!block)
1986                         continue;
1987
1988                 block->setLightingExpired(false);
1989         }
1990
1991         /*
1992                 Blit generated stuff to map
1993                 NOTE: blitBackAll adds nearly everything to changed_blocks
1994         */
1995         data->vmanip->blitBackAll(changed_blocks);
1996
1997         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()="
1998                 << changed_blocks->size());
1999
2000         /*
2001                 Copy transforming liquid information
2002         */
2003         while (data->transforming_liquid.size()) {
2004                 m_transforming_liquid.push_back(data->transforming_liquid.front());
2005                 data->transforming_liquid.pop_front();
2006         }
2007
2008         for (std::map<v3s16, MapBlock *>::iterator
2009                         it = changed_blocks->begin();
2010                         it != changed_blocks->end(); ++it) {
2011                 MapBlock *block = it->second;
2012                 if (!block)
2013                         continue;
2014                 /*
2015                         Update day/night difference cache of the MapBlocks
2016                 */
2017                 block->expireDayNightDiff();
2018                 /*
2019                         Set block as modified
2020                 */
2021                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2022                         MOD_REASON_EXPIRE_DAYNIGHTDIFF);
2023         }
2024
2025         /*
2026                 Set central blocks as generated
2027         */
2028         for (s16 x = bpmin.X; x <= bpmax.X; x++)
2029         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
2030         for (s16 y = bpmin.Y; y <= bpmax.Y; y++) {
2031                 MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
2032                 if (!block)
2033                         continue;
2034
2035                 block->setGenerated(true);
2036         }
2037
2038         /*
2039                 Save changed parts of map
2040                 NOTE: Will be saved later.
2041         */
2042         //save(MOD_STATE_WRITE_AT_UNLOAD);
2043 }
2044
2045 ServerMapSector *ServerMap::createSector(v2s16 p2d)
2046 {
2047         DSTACKF("%s: p2d=(%d,%d)",
2048                         FUNCTION_NAME,
2049                         p2d.X, p2d.Y);
2050
2051         /*
2052                 Check if it exists already in memory
2053         */
2054         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2055         if(sector != NULL)
2056                 return sector;
2057
2058         /*
2059                 Try to load it from disk (with blocks)
2060         */
2061         //if(loadSectorFull(p2d) == true)
2062
2063         /*
2064                 Try to load metadata from disk
2065         */
2066 #if 0
2067         if(loadSectorMeta(p2d) == true)
2068         {
2069                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2070                 if(sector == NULL)
2071                 {
2072                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2073                         throw InvalidPositionException("");
2074                 }
2075                 return sector;
2076         }
2077 #endif
2078         /*
2079                 Do not create over-limit
2080         */
2081         const static u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
2082                 g_settings->getU16("map_generation_limit"));
2083         if(p2d.X < -map_gen_limit / MAP_BLOCKSIZE
2084                         || p2d.X >  map_gen_limit / MAP_BLOCKSIZE
2085                         || p2d.Y < -map_gen_limit / MAP_BLOCKSIZE
2086                         || p2d.Y >  map_gen_limit / MAP_BLOCKSIZE)
2087                 throw InvalidPositionException("createSector(): pos. over limit");
2088
2089         /*
2090                 Generate blank sector
2091         */
2092
2093         sector = new ServerMapSector(this, p2d, m_gamedef);
2094
2095         // Sector position on map in nodes
2096         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2097
2098         /*
2099                 Insert to container
2100         */
2101         m_sectors[p2d] = sector;
2102
2103         return sector;
2104 }
2105
2106 #if 0
2107 /*
2108         This is a quick-hand function for calling makeBlock().
2109 */
2110 MapBlock * ServerMap::generateBlock(
2111                 v3s16 p,
2112                 std::map<v3s16, MapBlock*> &modified_blocks
2113 )
2114 {
2115         DSTACKF("%s: p=(%d,%d,%d)", FUNCTION_NAME, p.X, p.Y, p.Z);
2116
2117         /*infostream<<"generateBlock(): "
2118                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2119                         <<std::endl;*/
2120
2121         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2122
2123         TimeTaker timer("generateBlock");
2124
2125         //MapBlock *block = original_dummy;
2126
2127         v2s16 p2d(p.X, p.Z);
2128         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2129
2130         /*
2131                 Do not generate over-limit
2132         */
2133         if(blockpos_over_limit(p))
2134         {
2135                 infostream<<FUNCTION_NAME<<": Block position over limit"<<std::endl;
2136                 throw InvalidPositionException("generateBlock(): pos. over limit");
2137         }
2138
2139         /*
2140                 Create block make data
2141         */
2142         BlockMakeData data;
2143         initBlockMake(&data, p);
2144
2145         /*
2146                 Generate block
2147         */
2148         {
2149                 TimeTaker t("mapgen::make_block()");
2150                 mapgen->makeChunk(&data);
2151                 //mapgen::make_block(&data);
2152
2153                 if(enable_mapgen_debug_info == false)
2154                         t.stop(true); // Hide output
2155         }
2156
2157         /*
2158                 Blit data back on map, update lighting, add mobs and whatever this does
2159         */
2160         finishBlockMake(&data, modified_blocks);
2161
2162         /*
2163                 Get central block
2164         */
2165         MapBlock *block = getBlockNoCreateNoEx(p);
2166
2167 #if 0
2168         /*
2169                 Check result
2170         */
2171         if(block)
2172         {
2173                 bool erroneus_content = false;
2174                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2175                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2176                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2177                 {
2178                         v3s16 p(x0,y0,z0);
2179                         MapNode n = block->getNode(p);
2180                         if(n.getContent() == CONTENT_IGNORE)
2181                         {
2182                                 infostream<<"CONTENT_IGNORE at "
2183                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2184                                                 <<std::endl;
2185                                 erroneus_content = true;
2186                                 assert(0);
2187                         }
2188                 }
2189                 if(erroneus_content)
2190                 {
2191                         assert(0);
2192                 }
2193         }
2194 #endif
2195
2196 #if 0
2197         /*
2198                 Generate a completely empty block
2199         */
2200         if(block)
2201         {
2202                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2203                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2204                 {
2205                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2206                         {
2207                                 MapNode n;
2208                                 n.setContent(CONTENT_AIR);
2209                                 block->setNode(v3s16(x0,y0,z0), n);
2210                         }
2211                 }
2212         }
2213 #endif
2214
2215         if(enable_mapgen_debug_info == false)
2216                 timer.stop(true); // Hide output
2217
2218         return block;
2219 }
2220 #endif
2221
2222 MapBlock * ServerMap::createBlock(v3s16 p)
2223 {
2224         DSTACKF("%s: p=(%d,%d,%d)",
2225                         FUNCTION_NAME, p.X, p.Y, p.Z);
2226
2227         /*
2228                 Do not create over-limit
2229         */
2230         if (blockpos_over_limit(p))
2231                 throw InvalidPositionException("createBlock(): pos. over limit");
2232
2233         v2s16 p2d(p.X, p.Z);
2234         s16 block_y = p.Y;
2235         /*
2236                 This will create or load a sector if not found in memory.
2237                 If block exists on disk, it will be loaded.
2238
2239                 NOTE: On old save formats, this will be slow, as it generates
2240                       lighting on blocks for them.
2241         */
2242         ServerMapSector *sector;
2243         try {
2244                 sector = (ServerMapSector*)createSector(p2d);
2245                 assert(sector->getId() == MAPSECTOR_SERVER);
2246         }
2247         catch(InvalidPositionException &e)
2248         {
2249                 infostream<<"createBlock: createSector() failed"<<std::endl;
2250                 throw e;
2251         }
2252         /*
2253                 NOTE: This should not be done, or at least the exception
2254                 should not be passed on as std::exception, because it
2255                 won't be catched at all.
2256         */
2257         /*catch(std::exception &e)
2258         {
2259                 infostream<<"createBlock: createSector() failed: "
2260                                 <<e.what()<<std::endl;
2261                 throw e;
2262         }*/
2263
2264         /*
2265                 Try to get a block from the sector
2266         */
2267
2268         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2269         if(block)
2270         {
2271                 if(block->isDummy())
2272                         block->unDummify();
2273                 return block;
2274         }
2275         // Create blank
2276         block = sector->createBlankBlock(block_y);
2277
2278         return block;
2279 }
2280
2281 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
2282 {
2283         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
2284                         FUNCTION_NAME,
2285                         p.X, p.Y, p.Z, create_blank);
2286
2287         {
2288                 MapBlock *block = getBlockNoCreateNoEx(p);
2289                 if(block && block->isDummy() == false)
2290                         return block;
2291         }
2292
2293         {
2294                 MapBlock *block = loadBlock(p);
2295                 if(block)
2296                         return block;
2297         }
2298
2299         if (create_blank) {
2300                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
2301                 MapBlock *block = sector->createBlankBlock(p.Y);
2302
2303                 return block;
2304         }
2305
2306 #if 0
2307         if(allow_generate)
2308         {
2309                 std::map<v3s16, MapBlock*> modified_blocks;
2310                 MapBlock *block = generateBlock(p, modified_blocks);
2311                 if(block)
2312                 {
2313                         MapEditEvent event;
2314                         event.type = MEET_OTHER;
2315                         event.p = p;
2316
2317                         // Copy modified_blocks to event
2318                         for(std::map<v3s16, MapBlock*>::iterator
2319                                         i = modified_blocks.begin();
2320                                         i != modified_blocks.end(); ++i)
2321                         {
2322                                 event.modified_blocks.insert(i->first);
2323                         }
2324
2325                         // Queue event
2326                         dispatchEvent(&event);
2327
2328                         return block;
2329                 }
2330         }
2331 #endif
2332
2333         return NULL;
2334 }
2335
2336 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
2337 {
2338         MapBlock *block = getBlockNoCreateNoEx(p3d);
2339         if (block == NULL)
2340                 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
2341
2342         return block;
2343 }
2344
2345 void ServerMap::prepareBlock(MapBlock *block) {
2346 }
2347
2348 // N.B.  This requires no synchronization, since data will not be modified unless
2349 // the VoxelManipulator being updated belongs to the same thread.
2350 void ServerMap::updateVManip(v3s16 pos)
2351 {
2352         Mapgen *mg = m_emerge->getCurrentMapgen();
2353         if (!mg)
2354                 return;
2355
2356         MMVManip *vm = mg->vm;
2357         if (!vm)
2358                 return;
2359
2360         if (!vm->m_area.contains(pos))
2361                 return;
2362
2363         s32 idx = vm->m_area.index(pos);
2364         vm->m_data[idx] = getNodeNoEx(pos);
2365         vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA;
2366
2367         vm->m_is_dirty = true;
2368 }
2369
2370 s16 ServerMap::findGroundLevel(v2s16 p2d)
2371 {
2372 #if 0
2373         /*
2374                 Uh, just do something random...
2375         */
2376         // Find existing map from top to down
2377         s16 max=63;
2378         s16 min=-64;
2379         v3s16 p(p2d.X, max, p2d.Y);
2380         for(; p.Y>min; p.Y--)
2381         {
2382                 MapNode n = getNodeNoEx(p);
2383                 if(n.getContent() != CONTENT_IGNORE)
2384                         break;
2385         }
2386         if(p.Y == min)
2387                 goto plan_b;
2388         // If this node is not air, go to plan b
2389         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2390                 goto plan_b;
2391         // Search existing walkable and return it
2392         for(; p.Y>min; p.Y--)
2393         {
2394                 MapNode n = getNodeNoEx(p);
2395                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2396                         return p.Y;
2397         }
2398
2399         // Move to plan b
2400 plan_b:
2401 #endif
2402
2403         /*
2404                 Determine from map generator noise functions
2405         */
2406
2407         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
2408         return level;
2409
2410         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2411         //return (s16)level;
2412 }
2413
2414 bool ServerMap::loadFromFolders() {
2415         if (!dbase->initialized() &&
2416                         !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
2417                 return true;
2418         return false;
2419 }
2420
2421 void ServerMap::createDirs(std::string path)
2422 {
2423         if(fs::CreateAllDirs(path) == false)
2424         {
2425                 m_dout<<"ServerMap: Failed to create directory "
2426                                 <<"\""<<path<<"\""<<std::endl;
2427                 throw BaseException("ServerMap failed to create directory");
2428         }
2429 }
2430
2431 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2432 {
2433         char cc[9];
2434         switch(layout)
2435         {
2436                 case 1:
2437                         snprintf(cc, 9, "%.4x%.4x",
2438                                 (unsigned int) pos.X & 0xffff,
2439                                 (unsigned int) pos.Y & 0xffff);
2440
2441                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2442                 case 2:
2443                         snprintf(cc, 9, (std::string("%.3x") + DIR_DELIM + "%.3x").c_str(),
2444                                 (unsigned int) pos.X & 0xfff,
2445                                 (unsigned int) pos.Y & 0xfff);
2446
2447                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2448                 default:
2449                         assert(false);
2450                         return "";
2451         }
2452 }
2453
2454 v2s16 ServerMap::getSectorPos(std::string dirname)
2455 {
2456         unsigned int x = 0, y = 0;
2457         int r;
2458         std::string component;
2459         fs::RemoveLastPathComponent(dirname, &component, 1);
2460         if(component.size() == 8)
2461         {
2462                 // Old layout
2463                 r = sscanf(component.c_str(), "%4x%4x", &x, &y);
2464         }
2465         else if(component.size() == 3)
2466         {
2467                 // New layout
2468                 fs::RemoveLastPathComponent(dirname, &component, 2);
2469                 r = sscanf(component.c_str(), (std::string("%3x") + DIR_DELIM + "%3x").c_str(), &x, &y);
2470                 // Sign-extend the 12 bit values up to 16 bits...
2471                 if(x & 0x800) x |= 0xF000;
2472                 if(y & 0x800) y |= 0xF000;
2473         }
2474         else
2475         {
2476                 r = -1;
2477         }
2478
2479         FATAL_ERROR_IF(r != 2, "getSectorPos()");
2480         v2s16 pos((s16)x, (s16)y);
2481         return pos;
2482 }
2483
2484 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2485 {
2486         v2s16 p2d = getSectorPos(sectordir);
2487
2488         if(blockfile.size() != 4){
2489                 throw InvalidFilenameException("Invalid block filename");
2490         }
2491         unsigned int y;
2492         int r = sscanf(blockfile.c_str(), "%4x", &y);
2493         if(r != 1)
2494                 throw InvalidFilenameException("Invalid block filename");
2495         return v3s16(p2d.X, y, p2d.Y);
2496 }
2497
2498 std::string ServerMap::getBlockFilename(v3s16 p)
2499 {
2500         char cc[5];
2501         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2502         return cc;
2503 }
2504
2505 void ServerMap::save(ModifiedState save_level)
2506 {
2507         DSTACK(FUNCTION_NAME);
2508         if(m_map_saving_enabled == false) {
2509                 warningstream<<"Not saving map, saving disabled."<<std::endl;
2510                 return;
2511         }
2512
2513         if(save_level == MOD_STATE_CLEAN)
2514                 infostream<<"ServerMap: Saving whole map, this can take time."
2515                                 <<std::endl;
2516
2517         if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
2518                 if (settings_mgr.saveMapMeta())
2519                         m_map_metadata_changed = false;
2520         }
2521
2522         // Profile modified reasons
2523         Profiler modprofiler;
2524
2525         u32 sector_meta_count = 0;
2526         u32 block_count = 0;
2527         u32 block_count_all = 0; // Number of blocks in memory
2528
2529         // Don't do anything with sqlite unless something is really saved
2530         bool save_started = false;
2531
2532         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
2533                 i != m_sectors.end(); ++i) {
2534                 ServerMapSector *sector = (ServerMapSector*)i->second;
2535                 assert(sector->getId() == MAPSECTOR_SERVER);
2536
2537                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN) {
2538                         saveSectorMeta(sector);
2539                         sector_meta_count++;
2540                 }
2541
2542                 MapBlockVect blocks;
2543                 sector->getBlocks(blocks);
2544
2545                 for(MapBlockVect::iterator j = blocks.begin();
2546                         j != blocks.end(); ++j) {
2547                         MapBlock *block = *j;
2548
2549                         block_count_all++;
2550
2551                         if(block->getModified() >= (u32)save_level) {
2552                                 // Lazy beginSave()
2553                                 if(!save_started) {
2554                                         beginSave();
2555                                         save_started = true;
2556                                 }
2557
2558                                 modprofiler.add(block->getModifiedReasonString(), 1);
2559
2560                                 saveBlock(block);
2561                                 block_count++;
2562
2563                                 /*infostream<<"ServerMap: Written block ("
2564                                                 <<block->getPos().X<<","
2565                                                 <<block->getPos().Y<<","
2566                                                 <<block->getPos().Z<<")"
2567                                                 <<std::endl;*/
2568                         }
2569                 }
2570         }
2571
2572         if(save_started)
2573                 endSave();
2574
2575         /*
2576                 Only print if something happened or saved whole map
2577         */
2578         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
2579                         || block_count != 0) {
2580                 infostream<<"ServerMap: Written: "
2581                                 <<sector_meta_count<<" sector metadata files, "
2582                                 <<block_count<<" block files"
2583                                 <<", "<<block_count_all<<" blocks in memory."
2584                                 <<std::endl;
2585                 PrintInfo(infostream); // ServerMap/ClientMap:
2586                 infostream<<"Blocks modified by: "<<std::endl;
2587                 modprofiler.print(infostream);
2588         }
2589 }
2590
2591 void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
2592 {
2593         if (loadFromFolders()) {
2594                 errorstream << "Map::listAllLoadableBlocks(): Result will be missing "
2595                                 << "all blocks that are stored in flat files." << std::endl;
2596         }
2597         dbase->listAllLoadableBlocks(dst);
2598 }
2599
2600 void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
2601 {
2602         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
2603                 si != m_sectors.end(); ++si)
2604         {
2605                 MapSector *sector = si->second;
2606
2607                 MapBlockVect blocks;
2608                 sector->getBlocks(blocks);
2609
2610                 for(MapBlockVect::iterator i = blocks.begin();
2611                                 i != blocks.end(); ++i) {
2612                         v3s16 p = (*i)->getPos();
2613                         dst.push_back(p);
2614                 }
2615         }
2616 }
2617
2618 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2619 {
2620         DSTACK(FUNCTION_NAME);
2621         // Format used for writing
2622         u8 version = SER_FMT_VER_HIGHEST_WRITE;
2623         // Get destination
2624         v2s16 pos = sector->getPos();
2625         std::string dir = getSectorDir(pos);
2626         createDirs(dir);
2627
2628         std::string fullpath = dir + DIR_DELIM + "meta";
2629         std::ostringstream ss(std::ios_base::binary);
2630
2631         sector->serialize(ss, version);
2632
2633         if(!fs::safeWriteToFile(fullpath, ss.str()))
2634                 throw FileNotGoodException("Cannot write sector metafile");
2635
2636         sector->differs_from_disk = false;
2637 }
2638
2639 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
2640 {
2641         DSTACK(FUNCTION_NAME);
2642         // Get destination
2643         v2s16 p2d = getSectorPos(sectordir);
2644
2645         ServerMapSector *sector = NULL;
2646
2647         std::string fullpath = sectordir + DIR_DELIM + "meta";
2648         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2649         if(is.good() == false)
2650         {
2651                 // If the directory exists anyway, it probably is in some old
2652                 // format. Just go ahead and create the sector.
2653                 if(fs::PathExists(sectordir))
2654                 {
2655                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
2656                                         <<fullpath<<" doesn't exist but directory does."
2657                                         <<" Continuing with a sector with no metadata."
2658                                         <<std::endl;*/
2659                         sector = new ServerMapSector(this, p2d, m_gamedef);
2660                         m_sectors[p2d] = sector;
2661                 }
2662                 else
2663                 {
2664                         throw FileNotGoodException("Cannot open sector metafile");
2665                 }
2666         }
2667         else
2668         {
2669                 sector = ServerMapSector::deSerialize
2670                                 (is, this, p2d, m_sectors, m_gamedef);
2671                 if(save_after_load)
2672                         saveSectorMeta(sector);
2673         }
2674
2675         sector->differs_from_disk = false;
2676
2677         return sector;
2678 }
2679
2680 bool ServerMap::loadSectorMeta(v2s16 p2d)
2681 {
2682         DSTACK(FUNCTION_NAME);
2683
2684         // The directory layout we're going to load from.
2685         //  1 - original sectors/xxxxzzzz/
2686         //  2 - new sectors2/xxx/zzz/
2687         //  If we load from anything but the latest structure, we will
2688         //  immediately save to the new one, and remove the old.
2689         int loadlayout = 1;
2690         std::string sectordir1 = getSectorDir(p2d, 1);
2691         std::string sectordir;
2692         if(fs::PathExists(sectordir1))
2693         {
2694                 sectordir = sectordir1;
2695         }
2696         else
2697         {
2698                 loadlayout = 2;
2699                 sectordir = getSectorDir(p2d, 2);
2700         }
2701
2702         try{
2703                 loadSectorMeta(sectordir, loadlayout != 2);
2704         }
2705         catch(InvalidFilenameException &e)
2706         {
2707                 return false;
2708         }
2709         catch(FileNotGoodException &e)
2710         {
2711                 return false;
2712         }
2713         catch(std::exception &e)
2714         {
2715                 return false;
2716         }
2717
2718         return true;
2719 }
2720
2721 #if 0
2722 bool ServerMap::loadSectorFull(v2s16 p2d)
2723 {
2724         DSTACK(FUNCTION_NAME);
2725
2726         MapSector *sector = NULL;
2727
2728         // The directory layout we're going to load from.
2729         //  1 - original sectors/xxxxzzzz/
2730         //  2 - new sectors2/xxx/zzz/
2731         //  If we load from anything but the latest structure, we will
2732         //  immediately save to the new one, and remove the old.
2733         int loadlayout = 1;
2734         std::string sectordir1 = getSectorDir(p2d, 1);
2735         std::string sectordir;
2736         if(fs::PathExists(sectordir1))
2737         {
2738                 sectordir = sectordir1;
2739         }
2740         else
2741         {
2742                 loadlayout = 2;
2743                 sectordir = getSectorDir(p2d, 2);
2744         }
2745
2746         try{
2747                 sector = loadSectorMeta(sectordir, loadlayout != 2);
2748         }
2749         catch(InvalidFilenameException &e)
2750         {
2751                 return false;
2752         }
2753         catch(FileNotGoodException &e)
2754         {
2755                 return false;
2756         }
2757         catch(std::exception &e)
2758         {
2759                 return false;
2760         }
2761
2762         /*
2763                 Load blocks
2764         */
2765         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2766                         (sectordir);
2767         std::vector<fs::DirListNode>::iterator i2;
2768         for(i2=list2.begin(); i2!=list2.end(); i2++)
2769         {
2770                 // We want files
2771                 if(i2->dir)
2772                         continue;
2773                 try{
2774                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
2775                 }
2776                 catch(InvalidFilenameException &e)
2777                 {
2778                         // This catches unknown crap in directory
2779                 }
2780         }
2781
2782         if(loadlayout != 2)
2783         {
2784                 infostream<<"Sector converted to new layout - deleting "<<
2785                         sectordir1<<std::endl;
2786                 fs::RecursiveDelete(sectordir1);
2787         }
2788
2789         return true;
2790 }
2791 #endif
2792
2793 Database *ServerMap::createDatabase(
2794         const std::string &name,
2795         const std::string &savedir,
2796         Settings &conf)
2797 {
2798         if (name == "sqlite3")
2799                 return new Database_SQLite3(savedir);
2800         if (name == "dummy")
2801                 return new Database_Dummy();
2802         #if USE_LEVELDB
2803         else if (name == "leveldb")
2804                 return new Database_LevelDB(savedir);
2805         #endif
2806         #if USE_REDIS
2807         else if (name == "redis")
2808                 return new Database_Redis(conf);
2809         #endif
2810         #if USE_POSTGRESQL
2811         else if (name == "postgresql")
2812                 return new Database_PostgreSQL(conf);
2813         #endif
2814         else
2815                 throw BaseException(std::string("Database backend ") + name + " not supported.");
2816 }
2817
2818 void ServerMap::beginSave()
2819 {
2820         dbase->beginSave();
2821 }
2822
2823 void ServerMap::endSave()
2824 {
2825         dbase->endSave();
2826 }
2827
2828 bool ServerMap::saveBlock(MapBlock *block)
2829 {
2830         return saveBlock(block, dbase);
2831 }
2832
2833 bool ServerMap::saveBlock(MapBlock *block, Database *db)
2834 {
2835         v3s16 p3d = block->getPos();
2836
2837         // Dummy blocks are not written
2838         if (block->isDummy()) {
2839                 warningstream << "saveBlock: Not writing dummy block "
2840                         << PP(p3d) << std::endl;
2841                 return true;
2842         }
2843
2844         // Format used for writing
2845         u8 version = SER_FMT_VER_HIGHEST_WRITE;
2846
2847         /*
2848                 [0] u8 serialization version
2849                 [1] data
2850         */
2851         std::ostringstream o(std::ios_base::binary);
2852         o.write((char*) &version, 1);
2853         block->serialize(o, version, true);
2854
2855         std::string data = o.str();
2856         bool ret = db->saveBlock(p3d, data);
2857         if (ret) {
2858                 // We just wrote it to the disk so clear modified flag
2859                 block->resetModified();
2860         }
2861         return ret;
2862 }
2863
2864 void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
2865                 MapSector *sector, bool save_after_load)
2866 {
2867         DSTACK(FUNCTION_NAME);
2868
2869         std::string fullpath = sectordir + DIR_DELIM + blockfile;
2870         try {
2871
2872                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2873                 if(is.good() == false)
2874                         throw FileNotGoodException("Cannot open block file");
2875
2876                 v3s16 p3d = getBlockPos(sectordir, blockfile);
2877                 v2s16 p2d(p3d.X, p3d.Z);
2878
2879                 assert(sector->getPos() == p2d);
2880
2881                 u8 version = SER_FMT_VER_INVALID;
2882                 is.read((char*)&version, 1);
2883
2884                 if(is.fail())
2885                         throw SerializationError("ServerMap::loadBlock(): Failed"
2886                                         " to read MapBlock version");
2887
2888                 /*u32 block_size = MapBlock::serializedLength(version);
2889                 SharedBuffer<u8> data(block_size);
2890                 is.read((char*)*data, block_size);*/
2891
2892                 // This will always return a sector because we're the server
2893                 //MapSector *sector = emergeSector(p2d);
2894
2895                 MapBlock *block = NULL;
2896                 bool created_new = false;
2897                 block = sector->getBlockNoCreateNoEx(p3d.Y);
2898                 if(block == NULL)
2899                 {
2900                         block = sector->createBlankBlockNoInsert(p3d.Y);
2901                         created_new = true;
2902                 }
2903
2904                 // Read basic data
2905                 block->deSerialize(is, version, true);
2906
2907                 // If it's a new block, insert it to the map
2908                 if(created_new)
2909                         sector->insertBlock(block);
2910
2911                 /*
2912                         Save blocks loaded in old format in new format
2913                 */
2914
2915                 if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
2916                 {
2917                         saveBlock(block);
2918
2919                         // Should be in database now, so delete the old file
2920                         fs::RecursiveDelete(fullpath);
2921                 }
2922
2923                 // We just loaded it from the disk, so it's up-to-date.
2924                 block->resetModified();
2925
2926         }
2927         catch(SerializationError &e)
2928         {
2929                 warningstream<<"Invalid block data on disk "
2930                                 <<"fullpath="<<fullpath
2931                                 <<" (SerializationError). "
2932                                 <<"what()="<<e.what()
2933                                 <<std::endl;
2934                                 // Ignoring. A new one will be generated.
2935                 abort();
2936
2937                 // TODO: Backup file; name is in fullpath.
2938         }
2939 }
2940
2941 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
2942 {
2943         DSTACK(FUNCTION_NAME);
2944
2945         try {
2946                 std::istringstream is(*blob, std::ios_base::binary);
2947
2948                 u8 version = SER_FMT_VER_INVALID;
2949                 is.read((char*)&version, 1);
2950
2951                 if(is.fail())
2952                         throw SerializationError("ServerMap::loadBlock(): Failed"
2953                                         " to read MapBlock version");
2954
2955                 /*u32 block_size = MapBlock::serializedLength(version);
2956                 SharedBuffer<u8> data(block_size);
2957                 is.read((char*)*data, block_size);*/
2958
2959                 // This will always return a sector because we're the server
2960                 //MapSector *sector = emergeSector(p2d);
2961
2962                 MapBlock *block = NULL;
2963                 bool created_new = false;
2964                 block = sector->getBlockNoCreateNoEx(p3d.Y);
2965                 if(block == NULL)
2966                 {
2967                         block = sector->createBlankBlockNoInsert(p3d.Y);
2968                         created_new = true;
2969                 }
2970
2971                 // Read basic data
2972                 block->deSerialize(is, version, true);
2973
2974                 // If it's a new block, insert it to the map
2975                 if(created_new)
2976                         sector->insertBlock(block);
2977
2978                 /*
2979                         Save blocks loaded in old format in new format
2980                 */
2981
2982                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
2983                 // Only save if asked to; no need to update version
2984                 if(save_after_load)
2985                         saveBlock(block);
2986
2987                 // We just loaded it from, so it's up-to-date.
2988                 block->resetModified();
2989
2990         }
2991         catch(SerializationError &e)
2992         {
2993                 errorstream<<"Invalid block data in database"
2994                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
2995                                 <<" (SerializationError): "<<e.what()<<std::endl;
2996
2997                 // TODO: Block should be marked as invalid in memory so that it is
2998                 // not touched but the game can run
2999
3000                 if(g_settings->getBool("ignore_world_load_errors")){
3001                         errorstream<<"Ignoring block load error. Duck and cover! "
3002                                         <<"(ignore_world_load_errors)"<<std::endl;
3003                 } else {
3004                         throw SerializationError("Invalid block data in database");
3005                 }
3006         }
3007 }
3008
3009 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3010 {
3011         DSTACK(FUNCTION_NAME);
3012
3013         v2s16 p2d(blockpos.X, blockpos.Z);
3014
3015         std::string ret;
3016         dbase->loadBlock(blockpos, &ret);
3017         if (ret != "") {
3018                 loadBlock(&ret, blockpos, createSector(p2d), false);
3019                 return getBlockNoCreateNoEx(blockpos);
3020         }
3021         // Not found in database, try the files
3022
3023         // The directory layout we're going to load from.
3024         //  1 - original sectors/xxxxzzzz/
3025         //  2 - new sectors2/xxx/zzz/
3026         //  If we load from anything but the latest structure, we will
3027         //  immediately save to the new one, and remove the old.
3028         int loadlayout = 1;
3029         std::string sectordir1 = getSectorDir(p2d, 1);
3030         std::string sectordir;
3031         if(fs::PathExists(sectordir1))
3032         {
3033                 sectordir = sectordir1;
3034         }
3035         else
3036         {
3037                 loadlayout = 2;
3038                 sectordir = getSectorDir(p2d, 2);
3039         }
3040
3041         /*
3042                 Make sure sector is loaded
3043         */
3044
3045         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3046         if(sector == NULL)
3047         {
3048                 try{
3049                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3050                 }
3051                 catch(InvalidFilenameException &e)
3052                 {
3053                         return NULL;
3054                 }
3055                 catch(FileNotGoodException &e)
3056                 {
3057                         return NULL;
3058                 }
3059                 catch(std::exception &e)
3060                 {
3061                         return NULL;
3062                 }
3063         }
3064
3065         /*
3066                 Make sure file exists
3067         */
3068
3069         std::string blockfilename = getBlockFilename(blockpos);
3070         if(fs::PathExists(sectordir + DIR_DELIM + blockfilename) == false)
3071                 return NULL;
3072
3073         /*
3074                 Load block and save it to the database
3075         */
3076         loadBlock(sectordir, blockfilename, sector, true);
3077         return getBlockNoCreateNoEx(blockpos);
3078 }
3079
3080 bool ServerMap::deleteBlock(v3s16 blockpos)
3081 {
3082         if (!dbase->deleteBlock(blockpos))
3083                 return false;
3084
3085         MapBlock *block = getBlockNoCreateNoEx(blockpos);
3086         if (block) {
3087                 v2s16 p2d(blockpos.X, blockpos.Z);
3088                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
3089                 if (!sector)
3090                         return false;
3091                 sector->deleteBlock(block);
3092         }
3093
3094         return true;
3095 }
3096
3097 void ServerMap::PrintInfo(std::ostream &out)
3098 {
3099         out<<"ServerMap: ";
3100 }
3101
3102 MMVManip::MMVManip(Map *map):
3103                 VoxelManipulator(),
3104                 m_is_dirty(false),
3105                 m_create_area(false),
3106                 m_map(map)
3107 {
3108 }
3109
3110 MMVManip::~MMVManip()
3111 {
3112 }
3113
3114 void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
3115         bool load_if_inexistent)
3116 {
3117         TimeTaker timer1("initialEmerge", &emerge_time);
3118
3119         // Units of these are MapBlocks
3120         v3s16 p_min = blockpos_min;
3121         v3s16 p_max = blockpos_max;
3122
3123         VoxelArea block_area_nodes
3124                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3125
3126         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
3127         if(size_MB >= 1)
3128         {
3129                 infostream<<"initialEmerge: area: ";
3130                 block_area_nodes.print(infostream);
3131                 infostream<<" ("<<size_MB<<"MB)";
3132                 infostream<<std::endl;
3133         }
3134
3135         addArea(block_area_nodes);
3136
3137         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3138         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3139         for(s32 x=p_min.X; x<=p_max.X; x++)
3140         {
3141                 u8 flags = 0;
3142                 MapBlock *block;
3143                 v3s16 p(x,y,z);
3144                 std::map<v3s16, u8>::iterator n;
3145                 n = m_loaded_blocks.find(p);
3146                 if(n != m_loaded_blocks.end())
3147                         continue;
3148
3149                 bool block_data_inexistent = false;
3150                 try
3151                 {
3152                         TimeTaker timer1("emerge load", &emerge_load_time);
3153
3154                         block = m_map->getBlockNoCreate(p);
3155                         if(block->isDummy())
3156                                 block_data_inexistent = true;
3157                         else
3158                                 block->copyTo(*this);
3159                 }
3160                 catch(InvalidPositionException &e)
3161                 {
3162                         block_data_inexistent = true;
3163                 }
3164
3165                 if(block_data_inexistent)
3166                 {
3167
3168                         if (load_if_inexistent) {
3169                                 ServerMap *svrmap = (ServerMap *)m_map;
3170                                 block = svrmap->emergeBlock(p, false);
3171                                 if (block == NULL)
3172                                         block = svrmap->createBlock(p);
3173                                 block->copyTo(*this);
3174                         } else {
3175                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
3176
3177                                 /*
3178                                         Mark area inexistent
3179                                 */
3180                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3181                                 // Fill with VOXELFLAG_NO_DATA
3182                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3183                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3184                                 {
3185                                         s32 i = m_area.index(a.MinEdge.X,y,z);
3186                                         memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
3187                                 }
3188                         }
3189                 }
3190                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
3191                 {
3192                         // Mark that block was loaded as blank
3193                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
3194                 }*/
3195
3196                 m_loaded_blocks[p] = flags;
3197         }
3198
3199         m_is_dirty = false;
3200 }
3201
3202 void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
3203         bool overwrite_generated)
3204 {
3205         if(m_area.getExtent() == v3s16(0,0,0))
3206                 return;
3207
3208         /*
3209                 Copy data of all blocks
3210         */
3211         for(std::map<v3s16, u8>::iterator
3212                         i = m_loaded_blocks.begin();
3213                         i != m_loaded_blocks.end(); ++i)
3214         {
3215                 v3s16 p = i->first;
3216                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
3217                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
3218                 if ((existed == false) || (block == NULL) ||
3219                         (overwrite_generated == false && block->isGenerated() == true))
3220                         continue;
3221
3222                 block->copyFrom(*this);
3223
3224                 if(modified_blocks)
3225                         (*modified_blocks)[p] = block;
3226         }
3227 }
3228
3229 //END