]> git.lizzy.rs Git - minetest.git/blobdiff - src/map.cpp
Dungeongen: Fix out-of-voxelmanip access segfault
[minetest.git] / src / map.cpp
index 38a700e3c9f6ee06c06cef454328da8bd01ced8f..f2a4b7ffec02157e5188e0b3346c57dd76ab85ef 100644 (file)
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapblock.h"
 #include "filesys.h"
 #include "voxel.h"
+#include "voxelalgorithms.h"
 #include "porting.h"
 #include "serialization.h"
 #include "nodemetadata.h"
@@ -31,9 +32,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "nodedef.h"
 #include "gamedef.h"
 #include "util/directiontables.h"
-#include "util/mathconstants.h"
+#include "util/basic_macros.h"
 #include "rollback_interface.h"
 #include "environment.h"
+#include "reflowscan.h"
 #include "emerge.h"
 #include "mapgen_v6.h"
 #include "mg_biome.h"
@@ -50,8 +52,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #if USE_REDIS
 #include "database-redis.h"
 #endif
-
-#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
+#if USE_POSTGRESQL
+#include "database-postgresql.h"
+#endif
 
 
 /*
@@ -62,6 +65,7 @@ Map::Map(std::ostream &dout, IGameDef *gamedef):
        m_dout(dout),
        m_gamedef(gamedef),
        m_sector_cache(NULL),
+       m_nodedef(gamedef->ndef()),
        m_transforming_liquid_loop_count_multiplier(1.0f),
        m_unprocessed_count(0),
        m_inc_trending_up_start_time(0),
@@ -170,7 +174,7 @@ bool Map::isNodeUnderground(v3s16 p)
 bool Map::isValidPosition(v3s16 p)
 {
        v3s16 blockpos = getNodeBlockPos(p);
-       MapBlock *block = getBlockNoCreate(blockpos);
+       MapBlock *block = getBlockNoCreateNoEx(blockpos);
        return (block != NULL);
 }
 
@@ -223,7 +227,7 @@ void Map::setNode(v3s16 p, MapNode & n)
                bool temp_bool;
                errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE"
                                <<" while trying to replace \""
-                               <<m_gamedef->ndef()->get(block->getNodeNoCheck(relpos, &temp_bool)).name
+                               <<m_nodedef->get(block->getNodeNoCheck(relpos, &temp_bool)).name
                                <<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl;
                debug_stacks_print_to(infostream);
                return;
@@ -231,7 +235,6 @@ void Map::setNode(v3s16 p, MapNode & n)
        block->setNodeNoCheck(relpos, n);
 }
 
-
 /*
        Goes recursively through the neighbours of the node.
 
@@ -254,8 +257,6 @@ void Map::unspreadLight(enum LightBank bank,
                std::set<v3s16> & light_sources,
                std::map<v3s16, MapBlock*>  & modified_blocks)
 {
-       INodeDefManager *nodemgr = m_gamedef->ndef();
-
        v3s16 dirs[6] = {
                v3s16(0,0,1), // back
                v3s16(0,1,0), // top
@@ -350,20 +351,20 @@ void Map::unspreadLight(enum LightBank bank,
                                If the neighbor is dimmer than what was specified
                                as oldlight (the light of the previous node)
                        */
-                       if(n2.getLight(bank, nodemgr) < oldlight)
+                       if(n2.getLight(bank, m_nodedef) < oldlight)
                        {
                                /*
                                        And the neighbor is transparent and it has some light
                                */
-                               if(nodemgr->get(n2).light_propagates
-                                               && n2.getLight(bank, nodemgr) != 0)
+                               if(m_nodedef->get(n2).light_propagates
+                                               && n2.getLight(bank, m_nodedef) != 0)
                                {
                                        /*
                                                Set light to 0 and add to queue
                                        */
 
-                                       u8 current_light = n2.getLight(bank, nodemgr);
-                                       n2.setLight(bank, 0, nodemgr);
+                                       u8 current_light = n2.getLight(bank, m_nodedef);
+                                       n2.setLight(bank, 0, m_nodedef);
                                        block->setNode(relpos, n2);
 
                                        unlighted_nodes[n2pos] = current_light;
@@ -410,20 +411,6 @@ void Map::unspreadLight(enum LightBank bank,
                unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
 }
 
-/*
-       A single-node wrapper of the above
-*/
-void Map::unLightNeighbors(enum LightBank bank,
-               v3s16 pos, u8 lightwas,
-               std::set<v3s16> & light_sources,
-               std::map<v3s16, MapBlock*>  & modified_blocks)
-{
-       std::map<v3s16, u8> from_nodes;
-       from_nodes[pos] = lightwas;
-
-       unspreadLight(bank, from_nodes, light_sources, modified_blocks);
-}
-
 /*
        Lights neighbors of from_nodes, collects all them and then
        goes on recursively.
@@ -432,8 +419,6 @@ void Map::spreadLight(enum LightBank bank,
                std::set<v3s16> & from_nodes,
                std::map<v3s16, MapBlock*> & modified_blocks)
 {
-       INodeDefManager *nodemgr = m_gamedef->ndef();
-
        const v3s16 dirs[6] = {
                v3s16(0,0,1), // back
                v3s16(0,1,0), // top
@@ -487,7 +472,7 @@ void Map::spreadLight(enum LightBank bank,
                bool is_valid_position;
                MapNode n = block->getNode(relpos, &is_valid_position);
 
-               u8 oldlight = is_valid_position ? n.getLight(bank, nodemgr) : 0;
+               u8 oldlight = is_valid_position ? n.getLight(bank, m_nodedef) : 0;
                u8 newlight = diminish_light(oldlight);
 
                // Loop through 6 neighbors
@@ -523,7 +508,7 @@ void Map::spreadLight(enum LightBank bank,
                                If the neighbor is brighter than the current node,
                                add to list (it will light up this node on its turn)
                        */
-                       if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
+                       if(n2.getLight(bank, m_nodedef) > undiminish_light(oldlight))
                        {
                                lighted_nodes.insert(n2pos);
                                changed = true;
@@ -532,11 +517,11 @@ void Map::spreadLight(enum LightBank bank,
                                If the neighbor is dimmer than how much light this node
                                would spread on it, add to list
                        */
-                       if(n2.getLight(bank, nodemgr) < newlight)
+                       if(n2.getLight(bank, m_nodedef) < newlight)
                        {
-                               if(nodemgr->get(n2).light_propagates)
+                               if(m_nodedef->get(n2).light_propagates)
                                {
-                                       n2.setLight(bank, newlight, nodemgr);
+                                       n2.setLight(bank, newlight, m_nodedef);
                                        block->setNode(relpos, n2);
                                        lighted_nodes.insert(n2pos);
                                        changed = true;
@@ -565,115 +550,11 @@ void Map::spreadLight(enum LightBank bank,
                spreadLight(bank, lighted_nodes, modified_blocks);
 }
 
-/*
-       A single-node source variation of the above.
-*/
-void Map::lightNeighbors(enum LightBank bank,
-               v3s16 pos,
-               std::map<v3s16, MapBlock*> & modified_blocks)
-{
-       std::set<v3s16> from_nodes;
-       from_nodes.insert(pos);
-       spreadLight(bank, from_nodes, modified_blocks);
-}
-
-v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
-{
-       INodeDefManager *nodemgr = m_gamedef->ndef();
-
-       v3s16 dirs[6] = {
-               v3s16(0,0,1), // back
-               v3s16(0,1,0), // top
-               v3s16(1,0,0), // right
-               v3s16(0,0,-1), // front
-               v3s16(0,-1,0), // bottom
-               v3s16(-1,0,0), // left
-       };
-
-       u8 brightest_light = 0;
-       v3s16 brightest_pos(0,0,0);
-       bool found_something = false;
-
-       // Loop through 6 neighbors
-       for(u16 i=0; i<6; i++){
-               // Get the position of the neighbor node
-               v3s16 n2pos = p + dirs[i];
-               MapNode n2;
-               bool is_valid_position;
-               n2 = getNodeNoEx(n2pos, &is_valid_position);
-               if (!is_valid_position)
-                       continue;
-
-               if(n2.getLight(bank, nodemgr) > brightest_light || found_something == false){
-                       brightest_light = n2.getLight(bank, nodemgr);
-                       brightest_pos = n2pos;
-                       found_something = true;
-               }
-       }
-
-       if(found_something == false)
-               throw InvalidPositionException();
-
-       return brightest_pos;
-}
-
-/*
-       Propagates sunlight down from a node.
-       Starting point gets sunlight.
-
-       Returns the lowest y value of where the sunlight went.
-
-       Mud is turned into grass in where the sunlight stops.
-*/
-s16 Map::propagateSunlight(v3s16 start,
-               std::map<v3s16, MapBlock*> & modified_blocks)
-{
-       INodeDefManager *nodemgr = m_gamedef->ndef();
-
-       s16 y = start.Y;
-       for(; ; y--)
-       {
-               v3s16 pos(start.X, y, start.Z);
-
-               v3s16 blockpos = getNodeBlockPos(pos);
-               MapBlock *block;
-               try{
-                       block = getBlockNoCreate(blockpos);
-               }
-               catch(InvalidPositionException &e)
-               {
-                       break;
-               }
-
-               v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
-               bool is_valid_position;
-               MapNode n = block->getNode(relpos, &is_valid_position);
-               if (!is_valid_position)
-                       break;
-
-               if(nodemgr->get(n).sunlight_propagates)
-               {
-                       n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
-                       block->setNode(relpos, n);
-
-                       modified_blocks[blockpos] = block;
-               }
-               else
-               {
-                       // Sunlight goes no further
-                       break;
-               }
-       }
-       return y + 1;
-}
-
 void Map::updateLighting(enum LightBank bank,
                std::map<v3s16, MapBlock*> & a_blocks,
                std::map<v3s16, MapBlock*> & modified_blocks)
 {
-       INodeDefManager *nodemgr = m_gamedef->ndef();
-
-       /*m_dout<<DTIME<<"Map::updateLighting(): "
+       /*m_dout<<"Map::updateLighting(): "
                        <<a_blocks.size()<<" blocks."<<std::endl;*/
 
        //TimeTaker timer("updateLighting");
@@ -727,12 +608,12 @@ void Map::updateLighting(enum LightBank bank,
                                                        <<std::endl;
                                        continue;
                                }
-                               u8 oldlight = n.getLight(bank, nodemgr);
-                               n.setLight(bank, 0, nodemgr);
+                               u8 oldlight = n.getLight(bank, m_nodedef);
+                               n.setLight(bank, 0, m_nodedef);
                                block->setNode(p, n);
 
                                // If node sources light, add to list
-                               u8 source = nodemgr->get(n).light_source;
+                               u8 source = m_nodedef->get(n).light_source;
                                if(source != 0)
                                        light_sources.insert(p + posnodes);
 
@@ -919,150 +800,32 @@ void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
        }
 }
 
-/*
-*/
 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                std::map<v3s16, MapBlock*> &modified_blocks,
                bool remove_metadata)
 {
-       INodeDefManager *ndef = m_gamedef->ndef();
-
-       /*PrintInfo(m_dout);
-       m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
-                       <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-
-       /*
-               From this node to nodes underneath:
-               If lighting is sunlight (1.0), unlight neighbours and
-               set lighting to 0.
-               Else discontinue.
-       */
-
-       v3s16 toppos = p + v3s16(0,1,0);
-       //v3s16 bottompos = p + v3s16(0,-1,0);
-
-       bool node_under_sunlight = true;
-       std::set<v3s16> light_sources;
-
-       /*
-               Collect old node for rollback
-       */
+       // Collect old node for rollback
        RollbackNode rollback_oldnode(this, p, m_gamedef);
 
-       /*
-               If there is a node at top and it doesn't have sunlight,
-               there has not been any sunlight going down.
-
-               Otherwise there probably is.
-       */
-
-       bool is_valid_position;
-       MapNode topnode = getNodeNoEx(toppos, &is_valid_position);
-
-       if(is_valid_position && topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
-               node_under_sunlight = false;
-
-       /*
-               Remove all light that has come out of this node
-       */
+       // This is needed for updating the lighting
+       MapNode oldnode = getNodeNoEx(p);
 
-       enum LightBank banks[] =
-       {
-               LIGHTBANK_DAY,
-               LIGHTBANK_NIGHT
-       };
-       for(s32 i=0; i<2; i++)
-       {
-               enum LightBank bank = banks[i];
-
-               u8 lightwas = getNodeNoEx(p).getLight(bank, ndef);
-
-               // Add the block of the added node to modified_blocks
-               v3s16 blockpos = getNodeBlockPos(p);
-               MapBlock * block = getBlockNoCreate(blockpos);
-               assert(block != NULL);
-               modified_blocks[blockpos] = block;
-
-               assert(isValidPosition(p));
-
-               // Unlight neighbours of node.
-               // This means setting light of all consequent dimmer nodes
-               // to 0.
-               // This also collects the nodes at the border which will spread
-               // light again into this.
-               unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
-
-               n.setLight(bank, 0, ndef);
-       }
-
-       /*
-               If node lets sunlight through and is under sunlight, it has
-               sunlight too.
-       */
-       if(node_under_sunlight && ndef->get(n).sunlight_propagates)
-       {
-               n.setLight(LIGHTBANK_DAY, LIGHT_SUN, ndef);
-       }
-
-       /*
-               Remove node metadata
-       */
+       // Remove node metadata
        if (remove_metadata) {
                removeNodeMetadata(p);
        }
 
-       /*
-               Set the node on the map
-       */
-
+       // Set the node on the map
+       // Ignore light (because calling voxalgo::update_lighting_nodes)
+       n.setLight(LIGHTBANK_DAY, 0, m_nodedef);
+       n.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
        setNode(p, n);
 
-       /*
-               If node is under sunlight and doesn't let sunlight through,
-               take all sunlighted nodes under it and clear light from them
-               and from where the light has been spread.
-               TODO: This could be optimized by mass-unlighting instead
-                         of looping
-       */
-       if(node_under_sunlight && !ndef->get(n).sunlight_propagates)
-       {
-               s16 y = p.Y - 1;
-               for(;; y--){
-                       //m_dout<<DTIME<<"y="<<y<<std::endl;
-                       v3s16 n2pos(p.X, y, p.Z);
-
-                       MapNode n2;
+       // Update lighting
+       std::vector<std::pair<v3s16, MapNode> > oldnodes;
+       oldnodes.push_back(std::pair<v3s16, MapNode>(p, oldnode));
+       voxalgo::update_lighting_nodes(this, m_nodedef, oldnodes, modified_blocks);
 
-                       n2 = getNodeNoEx(n2pos, &is_valid_position);
-                       if (!is_valid_position)
-                               break;
-
-                       if(n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN)
-                       {
-                               unLightNeighbors(LIGHTBANK_DAY,
-                                               n2pos, n2.getLight(LIGHTBANK_DAY, ndef),
-                                               light_sources, modified_blocks);
-                               n2.setLight(LIGHTBANK_DAY, 0, ndef);
-                               setNode(n2pos, n2);
-                       }
-                       else
-                               break;
-               }
-       }
-
-       for(s32 i=0; i<2; i++)
-       {
-               enum LightBank bank = banks[i];
-
-               /*
-                       Spread light from all nodes that might be capable of doing so
-               */
-               spreadLight(bank, light_sources, modified_blocks);
-       }
-
-       /*
-               Update information about whether day and night light differ
-       */
        for(std::map<v3s16, MapBlock*>::iterator
                        i = modified_blocks.begin();
                        i != modified_blocks.end(); ++i)
@@ -1070,9 +833,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                i->second->expireDayNightDiff();
        }
 
-       /*
-               Report for rollback
-       */
+       // Report for rollback
        if(m_gamedef->rollback())
        {
                RollbackNode rollback_newnode(this, p, m_gamedef);
@@ -1082,208 +843,35 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        }
 
        /*
-               Add neighboring liquid nodes and the node itself if it is
-               liquid (=water node was added) to transform queue.
-       */
+               Add neighboring liquid nodes and this node to transform queue.
+               (it's vital for the node itself to get updated last, if it was removed.)
+        */
        v3s16 dirs[7] = {
-               v3s16(0,0,0), // self
                v3s16(0,0,1), // back
                v3s16(0,1,0), // top
                v3s16(1,0,0), // right
                v3s16(0,0,-1), // front
                v3s16(0,-1,0), // bottom
                v3s16(-1,0,0), // left
+               v3s16(0,0,0), // self
        };
        for(u16 i=0; i<7; i++)
        {
                v3s16 p2 = p + dirs[i];
 
+               bool is_valid_position;
                MapNode n2 = getNodeNoEx(p2, &is_valid_position);
-               if(is_valid_position
-                               && (ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR))
-               {
+               if(is_valid_position &&
+                               (m_nodedef->get(n2).isLiquid() ||
+                               n2.getContent() == CONTENT_AIR))
                        m_transforming_liquid.push_back(p2);
-               }
        }
 }
 
-/*
-*/
 void Map::removeNodeAndUpdate(v3s16 p,
                std::map<v3s16, MapBlock*> &modified_blocks)
 {
-       INodeDefManager *ndef = m_gamedef->ndef();
-
-       /*PrintInfo(m_dout);
-       m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
-                       <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-
-       bool node_under_sunlight = true;
-
-       v3s16 toppos = p + v3s16(0,1,0);
-
-       // Node will be replaced with this
-       content_t replace_material = CONTENT_AIR;
-
-       /*
-               Collect old node for rollback
-       */
-       RollbackNode rollback_oldnode(this, p, m_gamedef);
-
-       /*
-               If there is a node at top and it doesn't have sunlight,
-               there will be no sunlight going down.
-       */
-       bool is_valid_position;
-       MapNode topnode = getNodeNoEx(toppos, &is_valid_position);
-
-       if(is_valid_position && topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
-               node_under_sunlight = false;
-
-       std::set<v3s16> light_sources;
-
-       enum LightBank banks[] =
-       {
-               LIGHTBANK_DAY,
-               LIGHTBANK_NIGHT
-       };
-       for(s32 i=0; i<2; i++)
-       {
-               enum LightBank bank = banks[i];
-
-               /*
-                       Unlight neighbors (in case the node is a light source)
-               */
-               unLightNeighbors(bank, p,
-                               getNodeNoEx(p).getLight(bank, ndef),
-                               light_sources, modified_blocks);
-       }
-
-       /*
-               Remove node metadata
-       */
-
-       removeNodeMetadata(p);
-
-       /*
-               Remove the node.
-               This also clears the lighting.
-       */
-
-       MapNode n(replace_material);
-       setNode(p, n);
-
-       for(s32 i=0; i<2; i++)
-       {
-               enum LightBank bank = banks[i];
-
-               /*
-                       Recalculate lighting
-               */
-               spreadLight(bank, light_sources, modified_blocks);
-       }
-
-       // Add the block of the removed node to modified_blocks
-       v3s16 blockpos = getNodeBlockPos(p);
-       MapBlock * block = getBlockNoCreate(blockpos);
-       assert(block != NULL);
-       modified_blocks[blockpos] = block;
-
-       /*
-               If the removed node was under sunlight, propagate the
-               sunlight down from it and then light all neighbors
-               of the propagated blocks.
-       */
-       if(node_under_sunlight)
-       {
-               s16 ybottom = propagateSunlight(p, modified_blocks);
-               /*m_dout<<DTIME<<"Node was under sunlight. "
-                               "Propagating sunlight";
-               m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
-               s16 y = p.Y;
-               for(; y >= ybottom; y--)
-               {
-                       v3s16 p2(p.X, y, p.Z);
-                       /*m_dout<<DTIME<<"lighting neighbors of node ("
-                                       <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
-                                       <<std::endl;*/
-                       lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
-               }
-       }
-       else
-       {
-               // Set the lighting of this node to 0
-               // TODO: Is this needed? Lighting is cleared up there already.
-               MapNode n = getNodeNoEx(p, &is_valid_position);
-               if (is_valid_position) {
-                       n.setLight(LIGHTBANK_DAY, 0, ndef);
-                       setNode(p, n);
-               } else {
-                       FATAL_ERROR("Invalid position");
-               }
-       }
-
-       for(s32 i=0; i<2; i++)
-       {
-               enum LightBank bank = banks[i];
-
-               // Get the brightest neighbour node and propagate light from it
-               v3s16 n2p = getBrightestNeighbour(bank, p);
-               try{
-                       //MapNode n2 = getNode(n2p);
-                       lightNeighbors(bank, n2p, modified_blocks);
-               }
-               catch(InvalidPositionException &e)
-               {
-               }
-       }
-
-       /*
-               Update information about whether day and night light differ
-       */
-       for(std::map<v3s16, MapBlock*>::iterator
-                       i = modified_blocks.begin();
-                       i != modified_blocks.end(); ++i)
-       {
-               i->second->expireDayNightDiff();
-       }
-
-       /*
-               Report for rollback
-       */
-       if(m_gamedef->rollback())
-       {
-               RollbackNode rollback_newnode(this, p, m_gamedef);
-               RollbackAction action;
-               action.setSetNode(p, rollback_oldnode, rollback_newnode);
-               m_gamedef->rollback()->reportAction(action);
-       }
-
-       /*
-               Add neighboring liquid nodes and this node to transform queue.
-               (it's vital for the node itself to get updated last.)
-       */
-       v3s16 dirs[7] = {
-               v3s16(0,0,1), // back
-               v3s16(0,1,0), // top
-               v3s16(1,0,0), // right
-               v3s16(0,0,-1), // front
-               v3s16(0,-1,0), // bottom
-               v3s16(-1,0,0), // left
-               v3s16(0,0,0), // self
-       };
-       for(u16 i=0; i<7; i++)
-       {
-               v3s16 p2 = p + dirs[i];
-
-               bool is_position_valid;
-               MapNode n2 = getNodeNoEx(p2, &is_position_valid);
-               if (is_position_valid
-                               && (ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR))
-               {
-                       m_transforming_liquid.push_back(p2);
-               }
-       }
+       addNodeAndUpdate(p, MapNode(CONTENT_AIR), modified_blocks, true);
 }
 
 bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
@@ -1434,7 +1022,7 @@ void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks,
        beginSave();
 
        // If there is no practical limit, we spare creation of mapblock_queue
-       if (max_loaded_blocks == (u32)-1) {
+       if (max_loaded_blocks == U32_MAX) {
                for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
                                si != m_sectors.end(); ++si) {
                        MapSector *sector = si->second;
@@ -1499,8 +1087,8 @@ void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks,
                }
                block_count_all = mapblock_queue.size();
                // Delete old blocks, and blocks over the limit from the memory
-               while (mapblock_queue.size() > max_loaded_blocks
-                               || mapblock_queue.top().block->getUsageTimer() > unload_timeout) {
+               while (!mapblock_queue.empty() && (mapblock_queue.size() > max_loaded_blocks
+                               || mapblock_queue.top().block->getUsageTimer() > unload_timeout)) {
                        TimeOrderedMapBlock b = mapblock_queue.top();
                        mapblock_queue.pop();
 
@@ -1614,12 +1202,9 @@ s32 Map::transforming_liquid_size() {
         return m_transforming_liquid.size();
 }
 
-void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
+void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
 {
-
-       INodeDefManager *nodemgr = m_gamedef->ndef();
-
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        //TimeTaker timer("transformLiquids()");
 
        u32 loopcount = 0;
@@ -1631,8 +1216,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
        // list of nodes that due to viscosity have not reached their max level height
        std::deque<v3s16> must_reflow;
 
-       // List of MapBlocks that will require a lighting update (due to lava)
-       std::map<v3s16, MapBlock*> lighting_modified_blocks;
+       std::vector<std::pair<v3s16, MapNode> > changed_nodes;
 
        u32 liquid_loop_max = g_settings->getS32("liquid_loop_max");
        u32 loop_max = liquid_loop_max;
@@ -1654,10 +1238,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
        loop_max *= m_transforming_liquid_loop_count_multiplier;
 #endif
 
-       while(m_transforming_liquid.size() != 0)
+       while (m_transforming_liquid.size() != 0)
        {
                // This should be done here so that it is done when continue is used
-               if(loopcount >= initial_size || loopcount >= loop_max)
+               if (loopcount >= initial_size || loopcount >= loop_max)
                        break;
                loopcount++;
 
@@ -1673,22 +1257,29 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                        Collect information about current node
                 */
                s8 liquid_level = -1;
+               // The liquid node which will be placed there if
+               // the liquid flows into this node.
                content_t liquid_kind = CONTENT_IGNORE;
-               LiquidType liquid_type = nodemgr->get(n0).liquid_type;
+               // The node which will be placed there if liquid
+               // can't flow into this node.
+               content_t floodable_node = CONTENT_AIR;
+               const ContentFeatures &cf = m_nodedef->get(n0);
+               LiquidType liquid_type = cf.liquid_type;
                switch (liquid_type) {
                        case LIQUID_SOURCE:
                                liquid_level = LIQUID_LEVEL_SOURCE;
-                               liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing);
+                               liquid_kind = m_nodedef->getId(cf.liquid_alternative_flowing);
                                break;
                        case LIQUID_FLOWING:
                                liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
                                liquid_kind = n0.getContent();
                                break;
                        case LIQUID_NONE:
-                               // if this is an air node, it *could* be transformed into a liquid. otherwise,
-                               // continue with the next node.
-                               if (n0.getContent() != CONTENT_AIR)
+                               // if this node is 'floodable', it *could* be transformed
+                               // into a liquid, otherwise, continue with the next node.
+                               if (!cf.floodable)
                                        continue;
+                               floodable_node = n0.getContent();
                                liquid_kind = CONTENT_AIR;
                                break;
                }
@@ -1706,6 +1297,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
                int num_neutrals = 0;
                bool flowing_down = false;
+               bool ignored_sources = false;
                for (u16 i = 0; i < 6; i++) {
                        NeighborType nt = NEIGHBOR_SAME_LEVEL;
                        switch (i) {
@@ -1718,9 +1310,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                        }
                        v3s16 npos = p0 + dirs[i];
                        NodeNeighbor nb(getNodeNoEx(npos), nt, npos);
-                       switch (nodemgr->get(nb.n.getContent()).liquid_type) {
+                       const ContentFeatures &cfnb = m_nodedef->get(nb.n);
+                       switch (m_nodedef->get(nb.n.getContent()).liquid_type) {
                                case LIQUID_NONE:
-                                       if (nb.n.getContent() == CONTENT_AIR) {
+                                       if (cfnb.floodable) {
                                                airs[num_airs++] = nb;
                                                // if the current node is a water source the neighbor
                                                // should be enqueded for transformation regardless of whether the
@@ -1728,18 +1321,26 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                                                if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
                                                        m_transforming_liquid.push_back(npos);
                                                // if the current node happens to be a flowing node, it will start to flow down here.
-                                               if (nb.t == NEIGHBOR_LOWER) {
+                                               if (nb.t == NEIGHBOR_LOWER)
                                                        flowing_down = true;
-                                               }
                                        } else {
                                                neutrals[num_neutrals++] = nb;
+                                               if (nb.n.getContent() == CONTENT_IGNORE) {
+                                                       // If node below is ignore prevent water from
+                                                       // spreading outwards and otherwise prevent from
+                                                       // flowing away as ignore node might be the source
+                                                       if (nb.t == NEIGHBOR_LOWER)
+                                                               flowing_down = true;
+                                                       else
+                                                               ignored_sources = true;
+                                               }
                                        }
                                        break;
                                case LIQUID_SOURCE:
                                        // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
                                        if (liquid_kind == CONTENT_AIR)
-                                               liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
-                                       if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
+                                               liquid_kind = m_nodedef->getId(cfnb.liquid_alternative_flowing);
+                                       if (m_nodedef->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
                                                neutrals[num_neutrals++] = nb;
                                        } else {
                                                // Do not count bottom source, it will screw things up
@@ -1750,8 +1351,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                                case LIQUID_FLOWING:
                                        // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
                                        if (liquid_kind == CONTENT_AIR)
-                                               liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
-                                       if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
+                                               liquid_kind = m_nodedef->getId(cfnb.liquid_alternative_flowing);
+                                       if (m_nodedef->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
                                                neutrals[num_neutrals++] = nb;
                                        } else {
                                                flows[num_flows++] = nb;
@@ -1769,21 +1370,27 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                s8 new_node_level = -1;
                s8 max_node_level = -1;
 
-               u8 range = nodemgr->get(liquid_kind).liquid_range;
-               if (range > LIQUID_LEVEL_MAX+1)
-                       range = LIQUID_LEVEL_MAX+1;
+               u8 range = m_nodedef->get(liquid_kind).liquid_range;
+               if (range > LIQUID_LEVEL_MAX + 1)
+                       range = LIQUID_LEVEL_MAX + 1;
 
-               if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
+               if ((num_sources >= 2 && m_nodedef->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
                        // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
                        // or the flowing alternative of the first of the surrounding sources (if it's air), so
                        // it's perfectly safe to use liquid_kind here to determine the new node content.
-                       new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
+                       new_node_content = m_nodedef->getId(m_nodedef->get(liquid_kind).liquid_alternative_source);
                } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
                        // liquid_kind is set properly, see above
-                       new_node_content = liquid_kind;
                        max_node_level = new_node_level = LIQUID_LEVEL_MAX;
-                       if (new_node_level < (LIQUID_LEVEL_MAX+1-range))
-                               new_node_content = CONTENT_AIR;
+                       if (new_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
+                               new_node_content = liquid_kind;
+                       else
+                               new_node_content = floodable_node;
+               } else if (ignored_sources && liquid_level >= 0) {
+                       // Maybe there are neighbouring sources that aren't loaded yet
+                       // so prevent flowing away.
+                       new_node_level = liquid_level;
+                       new_node_content = liquid_kind;
                } else {
                        // no surrounding sources, so get the maximum level that can flow into this node
                        for (u16 i = 0; i < num_flows; i++) {
@@ -1794,21 +1401,21 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                                                        max_node_level = LIQUID_LEVEL_MAX;
                                                        if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
                                                                max_node_level = nb_liquid_level + WATER_DROP_BOOST;
-                                               } else if (nb_liquid_level > max_node_level)
+                                               } else if (nb_liquid_level > max_node_level) {
                                                        max_node_level = nb_liquid_level;
+                                               }
                                                break;
                                        case NEIGHBOR_LOWER:
                                                break;
                                        case NEIGHBOR_SAME_LEVEL:
                                                if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
-                                                       nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
+                                                               nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level)
                                                        max_node_level = nb_liquid_level - 1;
-                                               }
                                                break;
                                }
                        }
 
-                       u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
+                       u8 viscosity = m_nodedef->get(liquid_kind).liquid_viscosity;
                        if (viscosity > 1 && max_node_level != liquid_level) {
                                // amount to gain, limited by viscosity
                                // must be at least 1 in absolute value
@@ -1821,23 +1428,25 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                                        new_node_level = liquid_level + 1;
                                if (new_node_level != max_node_level)
                                        must_reflow.push_back(p0);
-                       } else
+                       } else {
                                new_node_level = max_node_level;
+                       }
 
-                       if (max_node_level >= (LIQUID_LEVEL_MAX+1-range))
+                       if (max_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
                                new_node_content = liquid_kind;
                        else
-                               new_node_content = CONTENT_AIR;
+                               new_node_content = floodable_node;
 
                }
 
                /*
                        check if anything has changed. if not, just continue with the next node.
                 */
-               if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
-                                                                                ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
-                                                                                ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
-                                                                                == flowing_down)))
+               if (new_node_content == n0.getContent() &&
+                               (m_nodedef->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
+                               ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
+                               ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
+                               == flowing_down)))
                        continue;
 
 
@@ -1846,7 +1455,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                 */
                MapNode n00 = n0;
                //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
-               if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
+               if (m_nodedef->get(new_node_content).liquid_type == LIQUID_FLOWING) {
                        // set level to last 3 bits, flowing down bit to 4th bit
                        n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
                } else {
@@ -1855,13 +1464,16 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                }
                n0.setContent(new_node_content);
 
+               // Ignore light (because calling voxalgo::update_lighting_nodes)
+               n0.setLight(LIGHTBANK_DAY, 0, m_nodedef);
+               n0.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
+
                // Find out whether there is a suspect for this action
                std::string suspect;
-               if(m_gamedef->rollback()) {
+               if (m_gamedef->rollback())
                        suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
-               }
 
-               if(m_gamedef->rollback() && !suspect.empty()){
+               if (m_gamedef->rollback() && !suspect.empty()) {
                        // Blame suspect
                        RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
                        // Get old node for rollback
@@ -1880,18 +1492,15 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
 
                v3s16 blockpos = getNodeBlockPos(p0);
                MapBlock *block = getBlockNoCreateNoEx(blockpos);
-               if(block != NULL) {
+               if (block != NULL) {
                        modified_blocks[blockpos] =  block;
-                       // If new or old node emits light, MapBlock requires lighting update
-                       if(nodemgr->get(n0).light_source != 0 ||
-                                       nodemgr->get(n00).light_source != 0)
-                               lighting_modified_blocks[block->getPos()] = block;
+                       changed_nodes.push_back(std::pair<v3s16, MapNode>(p0, n00));
                }
 
                /*
                        enqueue neighbors for update if neccessary
                 */
-               switch (nodemgr->get(n0.getContent()).liquid_type) {
+               switch (m_nodedef->get(n0.getContent()).liquid_type) {
                        case LIQUID_SOURCE:
                        case LIQUID_FLOWING:
                                // make sure source flows into all neighboring nodes
@@ -1914,7 +1523,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
        for (std::deque<v3s16>::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter)
                m_transforming_liquid.push_back(*iter);
 
-       updateLighting(lighting_modified_blocks, modified_blocks);
+       voxalgo::update_lighting_nodes(this, m_nodedef, changed_nodes, modified_blocks);
 
 
        /* ----------------------------------------------------------------------
@@ -2018,7 +1627,7 @@ NodeMetadata *Map::getNodeMetadata(v3s16 p)
                block = emergeBlock(blockpos, false);
        }
        if(!block){
-               infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
+               warningstream<<"Map::getNodeMetadata(): Block not found"
                                <<std::endl;
                return NULL;
        }
@@ -2037,7 +1646,7 @@ bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
                block = emergeBlock(blockpos, false);
        }
        if(!block){
-               infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
+               warningstream<<"Map::setNodeMetadata(): Block not found"
                                <<std::endl;
                return false;
        }
@@ -2052,7 +1661,7 @@ void Map::removeNodeMetadata(v3s16 p)
        MapBlock *block = getBlockNoCreateNoEx(blockpos);
        if(block == NULL)
        {
-               infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
+               warningstream<<"Map::removeNodeMetadata(): Block not found"
                                <<std::endl;
                return;
        }
@@ -2070,16 +1679,18 @@ NodeTimer Map::getNodeTimer(v3s16 p)
                block = emergeBlock(blockpos, false);
        }
        if(!block){
-               infostream<<"WARNING: Map::getNodeTimer(): Block not found"
+               warningstream<<"Map::getNodeTimer(): Block not found"
                                <<std::endl;
                return NodeTimer();
        }
        NodeTimer t = block->m_node_timers.get(p_rel);
-       return t;
+       NodeTimer nt(t.timeout, t.elapsed, p);
+       return nt;
 }
 
-void Map::setNodeTimer(v3s16 p, NodeTimer t)
+void Map::setNodeTimer(const NodeTimer &t)
 {
+       v3s16 p = t.position;
        v3s16 blockpos = getNodeBlockPos(p);
        v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
        MapBlock *block = getBlockNoCreateNoEx(blockpos);
@@ -2089,11 +1700,12 @@ void Map::setNodeTimer(v3s16 p, NodeTimer t)
                block = emergeBlock(blockpos, false);
        }
        if(!block){
-               infostream<<"WARNING: Map::setNodeTimer(): Block not found"
+               warningstream<<"Map::setNodeTimer(): Block not found"
                                <<std::endl;
                return;
        }
-       block->m_node_timers.set(p_rel, t);
+       NodeTimer nt(t.timeout, t.elapsed, p_rel);
+       block->m_node_timers.set(nt);
 }
 
 void Map::removeNodeTimer(v3s16 p)
@@ -2103,7 +1715,7 @@ void Map::removeNodeTimer(v3s16 p)
        MapBlock *block = getBlockNoCreateNoEx(blockpos);
        if(block == NULL)
        {
-               infostream<<"WARNING: Map::removeNodeTimer(): Block not found"
+               warningstream<<"Map::removeNodeTimer(): Block not found"
                                <<std::endl;
                return;
        }
@@ -2115,10 +1727,14 @@ void Map::removeNodeTimer(v3s16 p)
 */
 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
        Map(dout_server, gamedef),
+       settings_mgr(g_settings, savedir + DIR_DELIM + "map_meta.txt"),
        m_emerge(emerge),
        m_map_metadata_changed(true)
 {
-       verbosestream<<__FUNCTION_NAME<<std::endl;
+       verbosestream<<FUNCTION_NAME<<std::endl;
+
+       // Tell the EmergeManager about our MapSettingsManager
+       emerge->map_settings_mgr = &settings_mgr;
 
        /*
                Try to load map; if not found, create a new one.
@@ -2155,26 +1771,15 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer
                        }
                        else
                        {
-                               try{
-                                       // Load map metadata (seed, chunksize)
-                                       loadMapMeta();
-                               }
-                               catch(SettingNotFoundException &e){
-                                       infostream<<"ServerMap:  Some metadata not found."
-                                                         <<" Using default settings."<<std::endl;
-                               }
-                               catch(FileNotGoodException &e){
-                                       infostream<<"WARNING: Could not load map metadata"
-                                                       //<<" Disabling chunk-based generator."
-                                                       <<std::endl;
-                                       //m_chunksize = 0;
-                               }
 
-                               infostream<<"ServerMap: Successfully loaded map "
-                                               <<"metadata from "<<savedir
-                                               <<", assuming valid save directory."
-                                               <<" seed="<< m_emerge->params.seed <<"."
-                                               <<std::endl;
+                               if (settings_mgr.loadMapMeta()) {
+                                       infostream << "ServerMap: Metadata loaded from "
+                                               << savedir << std::endl;
+                               } else {
+                                       infostream << "ServerMap: Metadata could not be loaded "
+                                               "from " << savedir << ", assuming valid save "
+                                               "directory." << std::endl;
+                               }
 
                                m_map_saving_enabled = true;
                                // Map loaded, not creating new one
@@ -2188,10 +1793,10 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer
        }
        catch(std::exception &e)
        {
-               infostream<<"WARNING: ServerMap: Failed to load map from "<<savedir
+               warningstream<<"ServerMap: Failed to load map from "<<savedir
                                <<", exception: "<<e.what()<<std::endl;
                infostream<<"Please remove the map or fix it."<<std::endl;
-               infostream<<"WARNING: Map saving will be disabled."<<std::endl;
+               warningstream<<"Map saving will be disabled."<<std::endl;
        }
 
        infostream<<"Initializing new map."<<std::endl;
@@ -2205,7 +1810,7 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer
 
 ServerMap::~ServerMap()
 {
-       verbosestream<<__FUNCTION_NAME<<std::endl;
+       verbosestream<<FUNCTION_NAME<<std::endl;
 
        try
        {
@@ -2244,85 +1849,68 @@ ServerMap::~ServerMap()
 #endif
 }
 
+MapgenParams *ServerMap::getMapgenParams()
+{
+       // getMapgenParams() should only ever be called after Server is initialized
+       assert(settings_mgr.mapgen_params != NULL);
+       return settings_mgr.mapgen_params;
+}
+
 u64 ServerMap::getSeed()
 {
-       return m_emerge->params.seed;
+       return getMapgenParams()->seed;
 }
 
 s16 ServerMap::getWaterLevel()
 {
-       return m_emerge->params.water_level;
+       return getMapgenParams()->water_level;
 }
 
-bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
+bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
 {
-       bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
-       EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
+       s16 csize = getMapgenParams()->chunksize;
+       v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
+       v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
 
-       s16 chunksize = m_emerge->params.chunksize;
-       s16 coffset = -chunksize / 2;
-       v3s16 chunk_offset(coffset, coffset, coffset);
-       v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
-       v3s16 blockpos_min = blockpos_div * chunksize;
-       v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
-       blockpos_min += chunk_offset;
-       blockpos_max += chunk_offset;
+       bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
+       EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax));
 
-       v3s16 extra_borders(1,1,1);
+       v3s16 extra_borders(1, 1, 1);
+       v3s16 full_bpmin = bpmin - extra_borders;
+       v3s16 full_bpmax = bpmax + extra_borders;
 
        // Do nothing if not inside limits (+-1 because of neighbors)
-       if(blockpos_over_limit(blockpos_min - extra_borders) ||
-               blockpos_over_limit(blockpos_max + extra_borders))
+       if (blockpos_over_limit(full_bpmin) ||
+               blockpos_over_limit(full_bpmax))
                return false;
 
-       data->seed = m_emerge->params.seed;
-       data->blockpos_min = blockpos_min;
-       data->blockpos_max = blockpos_max;
+       data->seed = getSeed();
+       data->blockpos_min = bpmin;
+       data->blockpos_max = bpmax;
        data->blockpos_requested = blockpos;
-       data->nodedef = m_gamedef->ndef();
+       data->nodedef = m_nodedef;
 
        /*
                Create the whole area of this and the neighboring blocks
        */
-       {
-               //TimeTaker timer("initBlockMake() create area");
-
-               for(s16 x=blockpos_min.X-extra_borders.X;
-                               x<=blockpos_max.X+extra_borders.X; x++)
-               for(s16 z=blockpos_min.Z-extra_borders.Z;
-                               z<=blockpos_max.Z+extra_borders.Z; z++)
-               {
-                       v2s16 sectorpos(x, z);
-                       // Sector metadata is loaded from disk if not already loaded.
-                       ServerMapSector *sector = createSector(sectorpos);
-                       FATAL_ERROR_IF(sector == NULL, "createSector() failed");
-                       (void) sector;
-
-                       for(s16 y=blockpos_min.Y-extra_borders.Y;
-                                       y<=blockpos_max.Y+extra_borders.Y; y++)
-                       {
-                               v3s16 p(x,y,z);
-                               //MapBlock *block = createBlock(p);
-                               // 1) get from memory, 2) load from disk
-                               MapBlock *block = emergeBlock(p, false);
-                               // 3) create a blank one
-                               if(block == NULL)
-                               {
-                                       block = createBlock(p);
+       for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
+       for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) {
+               v2s16 sectorpos(x, z);
+               // Sector metadata is loaded from disk if not already loaded.
+               ServerMapSector *sector = createSector(sectorpos);
+               FATAL_ERROR_IF(sector == NULL, "createSector() failed");
+
+               for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
+                       v3s16 p(x, y, z);
 
-                                       /*
-                                               Block gets sunlight if this is true.
+                       MapBlock *block = emergeBlock(p, false);
+                       if (block == NULL) {
+                               block = createBlock(p);
 
-                                               Refer to the map generator heuristics.
-                                       */
-                                       bool ug = m_emerge->isBlockUnderground(p);
-                                       block->setIsUnderground(ug);
-                               }
-
-                               // Lighting will not be valid after make_chunk is called
-                               block->setLightingExpired(true);
-                               // Lighting will be calculated
-                               //block->setLightingExpired(false);
+                               // Block gets sunlight if this is true.
+                               // Refer to the map generator heuristics.
+                               bool ug = m_emerge->isBlockUnderground(p);
+                               block->setIsUnderground(ug);
                        }
                }
        }
@@ -2334,21 +1922,14 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
                neighboring blocks
        */
 
-       // The area that contains this block and it's neighbors
-       v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
-       v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
-
        data->vmanip = new MMVManip(this);
-       //data->vmanip->setMap(this);
+       data->vmanip->initialEmerge(full_bpmin, full_bpmax);
 
-       // Add the area
-       {
-               //TimeTaker timer("initBlockMake() initialEmerge");
-               data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
-       }
-
-       // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE
-/*     for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
+       // Note: we may need this again at some point.
+#if 0
+       // Ensure none of the blocks to be generated were marked as
+       // containing CONTENT_IGNORE
+       for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
                for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
                        for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
                                core::map<v3s16, u8>::Node *n;
@@ -2360,124 +1941,62 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
                                n->setValue(flags);
                        }
                }
-       }*/
+       }
+#endif
 
        // Data is ready now.
        return true;
 }
 
 void ServerMap::finishBlockMake(BlockMakeData *data,
-               std::map<v3s16, MapBlock*> &changed_blocks)
+       std::map<v3s16, MapBlock*> *changed_blocks)
 {
-       v3s16 blockpos_min = data->blockpos_min;
-       v3s16 blockpos_max = data->blockpos_max;
-       v3s16 blockpos_requested = data->blockpos_requested;
-       /*infostream<<"finishBlockMake(): ("<<blockpos_requested.X<<","
-                       <<blockpos_requested.Y<<","
-                       <<blockpos_requested.Z<<")"<<std::endl;*/
+       v3s16 bpmin = data->blockpos_min;
+       v3s16 bpmax = data->blockpos_max;
 
-       v3s16 extra_borders(1,1,1);
+       v3s16 extra_borders(1, 1, 1);
+       v3s16 full_bpmin = bpmin - extra_borders;
+       v3s16 full_bpmax = bpmax + extra_borders;
 
-       bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
+       bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
+       EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
 
-       /*infostream<<"Resulting vmanip:"<<std::endl;
-       data->vmanip.print(infostream);*/
+       /*
+               Set lighting to non-expired state in all of them.
+               This is cheating, but it is not fast enough if all of them
+               would actually be updated.
+       */
+       for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
+       for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++)
+       for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
+               MapBlock *block = emergeBlock(v3s16(x, y, z), false);
+               if (!block)
+                       continue;
 
-       // Make sure affected blocks are loaded
-       for(s16 x=blockpos_min.X-extra_borders.X;
-                       x<=blockpos_max.X+extra_borders.X; x++)
-       for(s16 z=blockpos_min.Z-extra_borders.Z;
-                       z<=blockpos_max.Z+extra_borders.Z; z++)
-       for(s16 y=blockpos_min.Y-extra_borders.Y;
-                       y<=blockpos_max.Y+extra_borders.Y; y++)
-       {
-               v3s16 p(x, y, z);
-               // Load from disk if not already in memory
-               emergeBlock(p, false);
+               block->setLightingExpired(false);
        }
 
        /*
                Blit generated stuff to map
                NOTE: blitBackAll adds nearly everything to changed_blocks
        */
-       {
-               // 70ms @cs=8
-               //TimeTaker timer("finishBlockMake() blitBackAll");
-               data->vmanip->blitBackAll(&changed_blocks);
-       }
+       data->vmanip->blitBackAll(changed_blocks);
 
-       EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
+       EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()="
+               << changed_blocks->size());
 
        /*
                Copy transforming liquid information
        */
-       while(data->transforming_liquid.size() > 0)
-       {
+       while (data->transforming_liquid.size()) {
                m_transforming_liquid.push_back(data->transforming_liquid.front());
                data->transforming_liquid.pop_front();
        }
 
-       /*
-               Do stuff in central blocks
-       */
-
-       /*
-               Update lighting
-       */
-       {
-#if 0
-               TimeTaker t("finishBlockMake lighting update");
-
-               core::map<v3s16, MapBlock*> lighting_update_blocks;
-
-               // Center blocks
-               for(s16 x=blockpos_min.X-extra_borders.X;
-                               x<=blockpos_max.X+extra_borders.X; x++)
-               for(s16 z=blockpos_min.Z-extra_borders.Z;
-                               z<=blockpos_max.Z+extra_borders.Z; z++)
-               for(s16 y=blockpos_min.Y-extra_borders.Y;
-                               y<=blockpos_max.Y+extra_borders.Y; y++)
-               {
-                       v3s16 p(x, y, z);
-                       MapBlock *block = getBlockNoCreateNoEx(p);
-                       assert(block);
-                       lighting_update_blocks.insert(block->getPos(), block);
-               }
-
-               updateLighting(lighting_update_blocks, changed_blocks);
-#endif
-
-               /*
-                       Set lighting to non-expired state in all of them.
-                       This is cheating, but it is not fast enough if all of them
-                       would actually be updated.
-               */
-               for(s16 x=blockpos_min.X-extra_borders.X;
-                               x<=blockpos_max.X+extra_borders.X; x++)
-               for(s16 z=blockpos_min.Z-extra_borders.Z;
-                               z<=blockpos_max.Z+extra_borders.Z; z++)
-               for(s16 y=blockpos_min.Y-extra_borders.Y;
-                               y<=blockpos_max.Y+extra_borders.Y; y++)
-               {
-                       v3s16 p(x, y, z);
-                       MapBlock * block = getBlockNoCreateNoEx(p);
-                       if (block != NULL)
-                               block->setLightingExpired(false);
-               }
-
-#if 0
-               if(enable_mapgen_debug_info == false)
-                       t.stop(true); // Hide output
-#endif
-       }
-
-       /*
-               Go through changed blocks
-       */
-       for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
-                       i != changed_blocks.end(); ++i)
-       {
-               MapBlock *block = i->second;
+       for (std::map<v3s16, MapBlock *>::iterator
+                       it = changed_blocks->begin();
+                       it != changed_blocks->end(); ++it) {
+               MapBlock *block = it->second;
                if (!block)
                        continue;
                /*
@@ -2494,14 +2013,13 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
        /*
                Set central blocks as generated
        */
-       for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)
-       for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)
-       for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++)
-       {
-               v3s16 p(x, y, z);
-               MapBlock *block = getBlockNoCreateNoEx(p);
+       for (s16 x = bpmin.X; x <= bpmax.X; x++)
+       for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
+       for (s16 y = bpmin.Y; y <= bpmax.Y; y++) {
+               MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
                if (!block)
                        continue;
+
                block->setGenerated(true);
        }
 
@@ -2510,42 +2028,12 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
                NOTE: Will be saved later.
        */
        //save(MOD_STATE_WRITE_AT_UNLOAD);
-
-       /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
-                       <<","<<blockpos_requested.Y<<","
-                       <<blockpos_requested.Z<<")"<<std::endl;*/
-
-
-#if 0
-       if(enable_mapgen_debug_info)
-       {
-               /*
-                       Analyze resulting blocks
-               */
-               /*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
-               for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
-               for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
-               for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
-               for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
-               for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
-               {
-                       v3s16 p = v3s16(x,y,z);
-                       MapBlock *block = getBlockNoCreateNoEx(p);
-                       char spos[20];
-                       snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
-                       infostream<<"Generated "<<spos<<": "
-                                       <<analyze_block(block)<<std::endl;
-               }
-       }
-#endif
-
-       getBlockNoCreateNoEx(blockpos_requested);
 }
 
-ServerMapSector * ServerMap::createSector(v2s16 p2d)
+ServerMapSector *ServerMap::createSector(v2s16 p2d)
 {
        DSTACKF("%s: p2d=(%d,%d)",
-                       __FUNCTION_NAME,
+                       FUNCTION_NAME,
                        p2d.X, p2d.Y);
 
        /*
@@ -2575,15 +2063,26 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
                return sector;
        }
 #endif
+
        /*
-               Do not create over-limit
+               Do not create over-limit.
+               We are checking for any nodes of the mapblocks of the sector being beyond the limit.
+               A sector is a vertical column of mapblocks, so sectorpos is like a 2D blockpos.
+
+               At the negative limit we are checking for
+                       block minimum nodepos < -mapgenlimit.
+               At the positive limit we are checking for
+                       block maximum nodepos > mapgenlimit.
+
+               Block minimum nodepos = blockpos * mapblocksize.
+               Block maximum nodepos = (blockpos + 1) * mapblocksize - 1.
        */
-       const static u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
+       const u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
                g_settings->getU16("map_generation_limit"));
-       if(p2d.X < -map_gen_limit / MAP_BLOCKSIZE
-                       || p2d.X >  map_gen_limit / MAP_BLOCKSIZE
-                       || p2d.Y < -map_gen_limit / MAP_BLOCKSIZE
-                       || p2d.Y >  map_gen_limit / MAP_BLOCKSIZE)
+       if (p2d.X * MAP_BLOCKSIZE < -map_gen_limit
+                       || (p2d.X + 1) * MAP_BLOCKSIZE - 1 > map_gen_limit
+                       || p2d.Y * MAP_BLOCKSIZE < -map_gen_limit
+                       || (p2d.Y + 1) * MAP_BLOCKSIZE - 1 > map_gen_limit)
                throw InvalidPositionException("createSector(): pos. over limit");
 
        /*
@@ -2612,7 +2111,7 @@ MapBlock * ServerMap::generateBlock(
                std::map<v3s16, MapBlock*> &modified_blocks
 )
 {
-       DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
+       DSTACKF("%s: p=(%d,%d,%d)", FUNCTION_NAME, p.X, p.Y, p.Z);
 
        /*infostream<<"generateBlock(): "
                        <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
@@ -2632,7 +2131,7 @@ MapBlock * ServerMap::generateBlock(
        */
        if(blockpos_over_limit(p))
        {
-               infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
+               infostream<<FUNCTION_NAME<<": Block position over limit"<<std::endl;
                throw InvalidPositionException("generateBlock(): pos. over limit");
        }
 
@@ -2722,7 +2221,7 @@ MapBlock * ServerMap::generateBlock(
 MapBlock * ServerMap::createBlock(v3s16 p)
 {
        DSTACKF("%s: p=(%d,%d,%d)",
-                       __FUNCTION_NAME, p.X, p.Y, p.Z);
+                       FUNCTION_NAME, p.X, p.Y, p.Z);
 
        /*
                Do not create over-limit
@@ -2781,7 +2280,7 @@ MapBlock * ServerMap::createBlock(v3s16 p)
 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
 {
        DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
-                       __FUNCTION_NAME,
+                       FUNCTION_NAME,
                        p.X, p.Y, p.Z, create_blank);
 
        {
@@ -2922,7 +2421,7 @@ void ServerMap::createDirs(std::string path)
 {
        if(fs::CreateAllDirs(path) == false)
        {
-               m_dout<<DTIME<<"ServerMap: Failed to create directory "
+               m_dout<<"ServerMap: Failed to create directory "
                                <<"\""<<path<<"\""<<std::endl;
                throw BaseException("ServerMap failed to create directory");
        }
@@ -3004,9 +2503,9 @@ std::string ServerMap::getBlockFilename(v3s16 p)
 
 void ServerMap::save(ModifiedState save_level)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        if(m_map_saving_enabled == false) {
-               infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
+               warningstream<<"Not saving map, saving disabled."<<std::endl;
                return;
        }
 
@@ -3014,8 +2513,9 @@ void ServerMap::save(ModifiedState save_level)
                infostream<<"ServerMap: Saving whole map, this can take time."
                                <<std::endl;
 
-       if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
-               saveMapMeta();
+       if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
+               if (settings_mgr.saveMapMeta())
+                       m_map_metadata_changed = false;
        }
 
        // Profile modified reasons
@@ -3114,58 +2614,9 @@ void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
        }
 }
 
-void ServerMap::saveMapMeta()
-{
-       DSTACK(__FUNCTION_NAME);
-
-       createDirs(m_savedir);
-
-       std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
-       std::ostringstream oss(std::ios_base::binary);
-       Settings conf;
-
-       m_emerge->params.save(conf);
-       conf.writeLines(oss);
-
-       oss << "[end_of_params]\n";
-
-       if(!fs::safeWriteToFile(fullpath, oss.str())) {
-               errorstream << "ServerMap::saveMapMeta(): "
-                               << "could not write " << fullpath << std::endl;
-               throw FileNotGoodException("Cannot save chunk metadata");
-       }
-
-       m_map_metadata_changed = false;
-}
-
-void ServerMap::loadMapMeta()
-{
-       DSTACK(__FUNCTION_NAME);
-
-       Settings conf;
-       std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
-
-       std::ifstream is(fullpath.c_str(), std::ios_base::binary);
-       if (!is.good()) {
-               errorstream << "ServerMap::loadMapMeta(): "
-                       "could not open " << fullpath << std::endl;
-               throw FileNotGoodException("Cannot open map metadata");
-       }
-
-       if (!conf.parseConfigLines(is, "[end_of_params]")) {
-               throw SerializationError("ServerMap::loadMapMeta(): "
-                               "[end_of_params] not found!");
-       }
-
-       m_emerge->params.load(conf);
-
-       verbosestream << "ServerMap::loadMapMeta(): seed="
-               << m_emerge->params.seed << std::endl;
-}
-
 void ServerMap::saveSectorMeta(ServerMapSector *sector)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        // Format used for writing
        u8 version = SER_FMT_VER_HIGHEST_WRITE;
        // Get destination
@@ -3186,7 +2637,7 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
 
 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
        // Get destination
        v2s16 p2d = getSectorPos(sectordir);
 
@@ -3227,7 +2678,7 @@ MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load
 
 bool ServerMap::loadSectorMeta(v2s16 p2d)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        // The directory layout we're going to load from.
        //  1 - original sectors/xxxxzzzz/
@@ -3269,7 +2720,7 @@ bool ServerMap::loadSectorMeta(v2s16 p2d)
 #if 0
 bool ServerMap::loadSectorFull(v2s16 p2d)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        MapSector *sector = NULL;
 
@@ -3338,7 +2789,10 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
 }
 #endif
 
-Database *ServerMap::createDatabase(const std::string &name, const std::string &savedir, Settings &conf)
+Database *ServerMap::createDatabase(
+       const std::string &name,
+       const std::string &savedir,
+       Settings &conf)
 {
        if (name == "sqlite3")
                return new Database_SQLite3(savedir);
@@ -3352,6 +2806,10 @@ Database *ServerMap::createDatabase(const std::string &name, const std::string &
        else if (name == "redis")
                return new Database_Redis(conf);
        #endif
+       #if USE_POSTGRESQL
+       else if (name == "postgresql")
+               return new Database_PostgreSQL(conf);
+       #endif
        else
                throw BaseException(std::string("Database backend ") + name + " not supported.");
 }
@@ -3377,7 +2835,7 @@ bool ServerMap::saveBlock(MapBlock *block, Database *db)
 
        // Dummy blocks are not written
        if (block->isDummy()) {
-               errorstream << "WARNING: saveBlock: Not writing dummy block "
+               warningstream << "saveBlock: Not writing dummy block "
                        << PP(p3d) << std::endl;
                return true;
        }
@@ -3405,7 +2863,7 @@ bool ServerMap::saveBlock(MapBlock *block, Database *db)
 void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
                MapSector *sector, bool save_after_load)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        std::string fullpath = sectordir + DIR_DELIM + blockfile;
        try {
@@ -3446,8 +2904,11 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
                block->deSerialize(is, version, true);
 
                // If it's a new block, insert it to the map
-               if(created_new)
+               if (created_new) {
                        sector->insertBlock(block);
+                       ReflowScan scanner(this, m_emerge->ndef);
+                       scanner.scan(block, &m_transforming_liquid);
+               }
 
                /*
                        Save blocks loaded in old format in new format
@@ -3467,7 +2928,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
        }
        catch(SerializationError &e)
        {
-               infostream<<"WARNING: Invalid block data on disk "
+               warningstream<<"Invalid block data on disk "
                                <<"fullpath="<<fullpath
                                <<" (SerializationError). "
                                <<"what()="<<e.what()
@@ -3481,7 +2942,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
 
 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        try {
                std::istringstream is(*blob, std::ios_base::binary);
@@ -3513,8 +2974,11 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
                block->deSerialize(is, version, true);
 
                // If it's a new block, insert it to the map
-               if(created_new)
+               if (created_new) {
                        sector->insertBlock(block);
+                       ReflowScan scanner(this, m_emerge->ndef);
+                       scanner.scan(block, &m_transforming_liquid);
+               }
 
                /*
                        Save blocks loaded in old format in new format
@@ -3549,13 +3013,12 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
 
 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
 {
-       DSTACK(__FUNCTION_NAME);
+       DSTACK(FUNCTION_NAME);
 
        v2s16 p2d(blockpos.X, blockpos.Z);
 
        std::string ret;
-
-       ret = dbase->loadBlock(blockpos);
+       dbase->loadBlock(blockpos, &ret);
        if (ret != "") {
                loadBlock(&ret, blockpos, createSector(p2d), false);
                return getBlockNoCreateNoEx(blockpos);
@@ -3583,6 +3046,7 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
        /*
                Make sure sector is loaded
        */
+
        MapSector *sector = getSectorNoGenerateNoEx(p2d);
        if(sector == NULL)
        {