]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/map.cpp
Implement GItlab CI daily builds for windows platform (32 & 64) (#5923)
[dragonfireclient.git] / src / map.cpp
index ffba772620e6576a7f777b5066dff6a192f13323..3b02ac02fc2dfd021a65cde98bd567428cffb160 100644 (file)
@@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "database.h"
 #include "database-dummy.h"
 #include "database-sqlite3.h"
+#include "script/scripting_server.h"
 #include <deque>
 #include <queue>
 #if USE_LEVELDB
@@ -235,571 +236,6 @@ void Map::setNode(v3s16 p, MapNode & n)
        block->setNodeNoCheck(relpos, n);
 }
 
-/*
-       Goes recursively through the neighbours of the node.
-
-       Alters only transparent nodes.
-
-       If the lighting of the neighbour is lower than the lighting of
-       the node was (before changing it to 0 at the step before), the
-       lighting of the neighbour is set to 0 and then the same stuff
-       repeats for the neighbour.
-
-       The ending nodes of the routine are stored in light_sources.
-       This is useful when a light is removed. In such case, this
-       routine can be called for the light node and then again for
-       light_sources to re-light the area without the removed light.
-
-       values of from_nodes are lighting values.
-*/
-void Map::unspreadLight(enum LightBank bank,
-               std::map<v3s16, u8> & from_nodes,
-               std::set<v3s16> & light_sources,
-               std::map<v3s16, MapBlock*>  & modified_blocks)
-{
-       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
-       };
-
-       if(from_nodes.empty())
-               return;
-
-       u32 blockchangecount = 0;
-
-       std::map<v3s16, u8> unlighted_nodes;
-
-       /*
-               Initialize block cache
-       */
-       v3s16 blockpos_last;
-       MapBlock *block = NULL;
-       // Cache this a bit, too
-       bool block_checked_in_modified = false;
-
-       for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
-               j != from_nodes.end(); ++j)
-       {
-               v3s16 pos = j->first;
-               v3s16 blockpos = getNodeBlockPos(pos);
-
-               // Only fetch a new block if the block position has changed
-               try{
-                       if(block == NULL || blockpos != blockpos_last){
-                               block = getBlockNoCreate(blockpos);
-                               blockpos_last = blockpos;
-
-                               block_checked_in_modified = false;
-                               blockchangecount++;
-                       }
-               }
-               catch(InvalidPositionException &e)
-               {
-                       continue;
-               }
-
-               if(block->isDummy())
-                       continue;
-
-               // Calculate relative position in block
-               //v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
-
-               // Get node straight from the block
-               //MapNode n = block->getNode(relpos);
-
-               u8 oldlight = j->second;
-
-               // Loop through 6 neighbors
-               for(u16 i=0; i<6; i++)
-               {
-                       // Get the position of the neighbor node
-                       v3s16 n2pos = pos + dirs[i];
-
-                       // Get the block where the node is located
-                       v3s16 blockpos, relpos;
-                       getNodeBlockPosWithOffset(n2pos, blockpos, relpos);
-
-                       // Only fetch a new block if the block position has changed
-                       try {
-                               if(block == NULL || blockpos != blockpos_last){
-                                       block = getBlockNoCreate(blockpos);
-                                       blockpos_last = blockpos;
-
-                                       block_checked_in_modified = false;
-                                       blockchangecount++;
-                               }
-                       }
-                       catch(InvalidPositionException &e) {
-                               continue;
-                       }
-
-                       // Get node straight from the block
-                       bool is_valid_position;
-                       MapNode n2 = block->getNode(relpos, &is_valid_position);
-                       if (!is_valid_position)
-                               continue;
-
-                       bool changed = false;
-
-                       //TODO: Optimize output by optimizing light_sources?
-
-                       /*
-                               If the neighbor is dimmer than what was specified
-                               as oldlight (the light of the previous node)
-                       */
-                       if(n2.getLight(bank, m_nodedef) < oldlight)
-                       {
-                               /*
-                                       And the neighbor is transparent and it has some light
-                               */
-                               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, m_nodedef);
-                                       n2.setLight(bank, 0, m_nodedef);
-                                       block->setNode(relpos, n2);
-
-                                       unlighted_nodes[n2pos] = current_light;
-                                       changed = true;
-
-                                       /*
-                                               Remove from light_sources if it is there
-                                               NOTE: This doesn't happen nearly at all
-                                       */
-                                       /*if(light_sources.find(n2pos))
-                                       {
-                                               infostream<<"Removed from light_sources"<<std::endl;
-                                               light_sources.remove(n2pos);
-                                       }*/
-                               }
-
-                               /*// DEBUG
-                               if(light_sources.find(n2pos) != NULL)
-                                       light_sources.remove(n2pos);*/
-                       }
-                       else{
-                               light_sources.insert(n2pos);
-                       }
-
-                       // Add to modified_blocks
-                       if(changed == true && block_checked_in_modified == false)
-                       {
-                               // If the block is not found in modified_blocks, add.
-                               if(modified_blocks.find(blockpos) == modified_blocks.end())
-                               {
-                                       modified_blocks[blockpos] = block;
-                               }
-                               block_checked_in_modified = true;
-                       }
-               }
-       }
-
-       /*infostream<<"unspreadLight(): Changed block "
-       <<blockchangecount<<" times"
-       <<" for "<<from_nodes.size()<<" nodes"
-       <<std::endl;*/
-
-       if(!unlighted_nodes.empty())
-               unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
-}
-
-/*
-       Lights neighbors of from_nodes, collects all them and then
-       goes on recursively.
-*/
-void Map::spreadLight(enum LightBank bank,
-               std::set<v3s16> & from_nodes,
-               std::map<v3s16, MapBlock*> & modified_blocks)
-{
-       const 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
-       };
-
-       if(from_nodes.empty())
-               return;
-
-       u32 blockchangecount = 0;
-
-       std::set<v3s16> lighted_nodes;
-
-       /*
-               Initialize block cache
-       */
-       v3s16 blockpos_last;
-       MapBlock *block = NULL;
-               // Cache this a bit, too
-       bool block_checked_in_modified = false;
-
-       for(std::set<v3s16>::iterator j = from_nodes.begin();
-               j != from_nodes.end(); ++j)
-       {
-               v3s16 pos = *j;
-               v3s16 blockpos, relpos;
-
-               getNodeBlockPosWithOffset(pos, blockpos, relpos);
-
-               // Only fetch a new block if the block position has changed
-               try {
-                       if(block == NULL || blockpos != blockpos_last){
-                               block = getBlockNoCreate(blockpos);
-                               blockpos_last = blockpos;
-
-                               block_checked_in_modified = false;
-                               blockchangecount++;
-                       }
-               }
-               catch(InvalidPositionException &e) {
-                       continue;
-               }
-
-               if(block->isDummy())
-                       continue;
-
-               // Get node straight from the block
-               bool is_valid_position;
-               MapNode n = block->getNode(relpos, &is_valid_position);
-
-               u8 oldlight = is_valid_position ? n.getLight(bank, m_nodedef) : 0;
-               u8 newlight = diminish_light(oldlight);
-
-               // Loop through 6 neighbors
-               for(u16 i=0; i<6; i++){
-                       // Get the position of the neighbor node
-                       v3s16 n2pos = pos + dirs[i];
-
-                       // Get the block where the node is located
-                       v3s16 blockpos, relpos;
-                       getNodeBlockPosWithOffset(n2pos, blockpos, relpos);
-
-                       // Only fetch a new block if the block position has changed
-                       try {
-                               if(block == NULL || blockpos != blockpos_last){
-                                       block = getBlockNoCreate(blockpos);
-                                       blockpos_last = blockpos;
-
-                                       block_checked_in_modified = false;
-                                       blockchangecount++;
-                               }
-                       }
-                       catch(InvalidPositionException &e) {
-                               continue;
-                       }
-
-                       // Get node straight from the block
-                       MapNode n2 = block->getNode(relpos, &is_valid_position);
-                       if (!is_valid_position)
-                               continue;
-
-                       bool changed = false;
-                       /*
-                               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, m_nodedef) > undiminish_light(oldlight))
-                       {
-                               lighted_nodes.insert(n2pos);
-                               changed = true;
-                       }
-                       /*
-                               If the neighbor is dimmer than how much light this node
-                               would spread on it, add to list
-                       */
-                       if(n2.getLight(bank, m_nodedef) < newlight)
-                       {
-                               if(m_nodedef->get(n2).light_propagates)
-                               {
-                                       n2.setLight(bank, newlight, m_nodedef);
-                                       block->setNode(relpos, n2);
-                                       lighted_nodes.insert(n2pos);
-                                       changed = true;
-                               }
-                       }
-
-                       // Add to modified_blocks
-                       if(changed == true && block_checked_in_modified == false)
-                       {
-                               // If the block is not found in modified_blocks, add.
-                               if(modified_blocks.find(blockpos) == modified_blocks.end())
-                               {
-                                       modified_blocks[blockpos] = block;
-                               }
-                               block_checked_in_modified = true;
-                       }
-               }
-       }
-
-       /*infostream<<"spreadLight(): Changed block "
-                       <<blockchangecount<<" times"
-                       <<" for "<<from_nodes.size()<<" nodes"
-                       <<std::endl;*/
-
-       if(!lighted_nodes.empty())
-               spreadLight(bank, lighted_nodes, modified_blocks);
-}
-
-void Map::updateLighting(enum LightBank bank,
-               std::map<v3s16, MapBlock*> & a_blocks,
-               std::map<v3s16, MapBlock*> & modified_blocks)
-{
-       /*m_dout<<"Map::updateLighting(): "
-                       <<a_blocks.size()<<" blocks."<<std::endl;*/
-
-       //TimeTaker timer("updateLighting");
-
-       // For debugging
-       //bool debug=true;
-       //u32 count_was = modified_blocks.size();
-
-       //std::map<v3s16, MapBlock*> blocks_to_update;
-
-       std::set<v3s16> light_sources;
-
-       std::map<v3s16, u8> unlight_from;
-
-       int num_bottom_invalid = 0;
-
-       {
-       //TimeTaker t("first stuff");
-
-       for(std::map<v3s16, MapBlock*>::iterator i = a_blocks.begin();
-               i != a_blocks.end(); ++i)
-       {
-               MapBlock *block = i->second;
-
-               for(;;)
-               {
-                       // Don't bother with dummy blocks.
-                       if(block->isDummy())
-                               break;
-
-                       v3s16 pos = block->getPos();
-                       v3s16 posnodes = block->getPosRelative();
-                       modified_blocks[pos] = block;
-                       //blocks_to_update[pos] = block;
-
-                       /*
-                               Clear all light from block
-                       */
-                       for(s16 z=0; z<MAP_BLOCKSIZE; z++)
-                       for(s16 x=0; x<MAP_BLOCKSIZE; x++)
-                       for(s16 y=0; y<MAP_BLOCKSIZE; y++)
-                       {
-                               v3s16 p(x,y,z);
-                               bool is_valid_position;
-                               MapNode n = block->getNode(p, &is_valid_position);
-                               if (!is_valid_position) {
-                                       /* This would happen when dealing with a
-                                          dummy block.
-                                       */
-                                       infostream<<"updateLighting(): InvalidPositionException"
-                                                       <<std::endl;
-                                       continue;
-                               }
-                               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 = m_nodedef->get(n).light_source;
-                               if(source != 0)
-                                       light_sources.insert(p + posnodes);
-
-                               // Collect borders for unlighting
-                               if((x==0 || x == MAP_BLOCKSIZE-1
-                                               || y==0 || y == MAP_BLOCKSIZE-1
-                                               || z==0 || z == MAP_BLOCKSIZE-1)
-                                               && oldlight != 0)
-                               {
-                                       v3s16 p_map = p + posnodes;
-                                       unlight_from[p_map] = oldlight;
-                               }
-
-
-                       }
-
-                       if(bank == LIGHTBANK_DAY)
-                       {
-                               bool bottom_valid = block->propagateSunlight(light_sources);
-
-                               if(!bottom_valid)
-                                       num_bottom_invalid++;
-
-                               // If bottom is valid, we're done.
-                               if(bottom_valid)
-                                       break;
-                       }
-                       else if(bank == LIGHTBANK_NIGHT)
-                       {
-                               // For night lighting, sunlight is not propagated
-                               break;
-                       }
-                       else
-                       {
-                               assert("Invalid lighting bank" == NULL);
-                       }
-
-                       /*infostream<<"Bottom for sunlight-propagated block ("
-                                       <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
-                                       <<std::endl;*/
-
-                       // Bottom sunlight is not valid; get the block and loop to it
-
-                       pos.Y--;
-                       try{
-                               block = getBlockNoCreate(pos);
-                       }
-                       catch(InvalidPositionException &e)
-                       {
-                               FATAL_ERROR("Invalid position");
-                       }
-
-               }
-       }
-
-       }
-
-       /*
-               Enable this to disable proper lighting for speeding up map
-               generation for testing or whatever
-       */
-#if 0
-       //if(g_settings->get(""))
-       {
-               core::map<v3s16, MapBlock*>::Iterator i;
-               i = blocks_to_update.getIterator();
-               for(; i.atEnd() == false; i++)
-               {
-                       MapBlock *block = i.getNode()->getValue();
-                       v3s16 p = block->getPos();
-                       block->setLightingExpired(false);
-               }
-               return;
-       }
-#endif
-
-#if 1
-       {
-               //TimeTaker timer("unspreadLight");
-               unspreadLight(bank, unlight_from, light_sources, modified_blocks);
-       }
-
-       /*if(debug)
-       {
-               u32 diff = modified_blocks.size() - count_was;
-               count_was = modified_blocks.size();
-               infostream<<"unspreadLight modified "<<diff<<std::endl;
-       }*/
-
-       {
-               //TimeTaker timer("spreadLight");
-               spreadLight(bank, light_sources, modified_blocks);
-       }
-
-       /*if(debug)
-       {
-               u32 diff = modified_blocks.size() - count_was;
-               count_was = modified_blocks.size();
-               infostream<<"spreadLight modified "<<diff<<std::endl;
-       }*/
-#endif
-
-#if 0
-       {
-               //MapVoxelManipulator vmanip(this);
-
-               // Make a manual voxel manipulator and load all the blocks
-               // that touch the requested blocks
-               ManualMapVoxelManipulator vmanip(this);
-
-               {
-               //TimeTaker timer("initialEmerge");
-
-               core::map<v3s16, MapBlock*>::Iterator i;
-               i = blocks_to_update.getIterator();
-               for(; i.atEnd() == false; i++)
-               {
-                       MapBlock *block = i.getNode()->getValue();
-                       v3s16 p = block->getPos();
-
-                       // Add all surrounding blocks
-                       vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
-
-                       /*
-                               Add all surrounding blocks that have up-to-date lighting
-                               NOTE: This doesn't quite do the job (not everything
-                                         appropriate is lighted)
-                       */
-                       /*for(s16 z=-1; z<=1; z++)
-                       for(s16 y=-1; y<=1; y++)
-                       for(s16 x=-1; x<=1; x++)
-                       {
-                               v3s16 p2 = p + v3s16(x,y,z);
-                               MapBlock *block = getBlockNoCreateNoEx(p2);
-                               if(block == NULL)
-                                       continue;
-                               if(block->isDummy())
-                                       continue;
-                               if(block->getLightingExpired())
-                                       continue;
-                               vmanip.initialEmerge(p2, p2);
-                       }*/
-
-                       // Lighting of block will be updated completely
-                       block->setLightingExpired(false);
-               }
-               }
-
-               {
-                       //TimeTaker timer("unSpreadLight");
-                       vmanip.unspreadLight(bank, unlight_from, light_sources, nodemgr);
-               }
-               {
-                       //TimeTaker timer("spreadLight");
-                       vmanip.spreadLight(bank, light_sources, nodemgr);
-               }
-               {
-                       //TimeTaker timer("blitBack");
-                       vmanip.blitBack(modified_blocks);
-               }
-               /*infostream<<"emerge_time="<<emerge_time<<std::endl;
-               emerge_time = 0;*/
-       }
-#endif
-
-       //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
-}
-
-void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
-               std::map<v3s16, MapBlock*> & modified_blocks)
-{
-       updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
-       updateLighting(LIGHTBANK_NIGHT, a_blocks, 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)
-       {
-               MapBlock *block = i->second;
-               block->expireDayNightDiff();
-       }
-}
-
 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                std::map<v3s16, MapBlock*> &modified_blocks,
                bool remove_metadata)
@@ -1202,7 +638,8 @@ 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,
+               ServerEnvironment *env)
 {
        DSTACK(FUNCTION_NAME);
        //TimeTaker timer("transformLiquids()");
@@ -1462,8 +899,16 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
                        // set the liquid level and flow bit to 0
                        n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
                }
+
+               // change the node.
                n0.setContent(new_node_content);
 
+               // on_flood() the node
+               if (floodable_node != CONTENT_AIR) {
+                       if (env->getScriptIface()->node_on_flood(p0, n00, n0))
+                               continue;
+               }
+
                // Ignore light (because calling voxalgo::update_lighting_nodes)
                n0.setLight(LIGHTBANK_DAY, 0, m_nodedef);
                n0.setLight(LIGHTBANK_NIGHT, 0, m_nodedef);
@@ -1536,7 +981,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
 
        time_until_purge *= 1000;       // seconds -> milliseconds
 
-       u32 curr_time = getTime(PRECISION_MILLI);
+       u64 curr_time = porting::getTimeMs();
        u32 prev_unprocessed = m_unprocessed_count;
        m_unprocessed_count = m_transforming_liquid.size();
 
@@ -1722,10 +1167,77 @@ void Map::removeNodeTimer(v3s16 p)
        block->m_node_timers.remove(p_rel);
 }
 
+bool Map::isOccluded(v3s16 p0, v3s16 p1, float step, float stepfac,
+               float start_off, float end_off, u32 needed_count)
+{
+       float d0 = (float)BS * p0.getDistanceFrom(p1);
+       v3s16 u0 = p1 - p0;
+       v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS;
+       uf.normalize();
+       v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS;
+       u32 count = 0;
+       for(float s=start_off; s<d0+end_off; s+=step){
+               v3f pf = p0f + uf * s;
+               v3s16 p = floatToInt(pf, BS);
+               MapNode n = getNodeNoEx(p);
+               const ContentFeatures &f = m_nodedef->get(n);
+               if(f.drawtype == NDT_NORMAL){
+                       // not transparent, see ContentFeature::updateTextures
+                       count++;
+                       if(count >= needed_count)
+                               return true;
+               }
+               step *= stepfac;
+       }
+       return false;
+}
+
+bool Map::isBlockOccluded(MapBlock *block, v3s16 cam_pos_nodes) {
+       v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
+       cpn += v3s16(MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2, MAP_BLOCKSIZE / 2);
+       float step = BS * 1;
+       float stepfac = 1.1;
+       float startoff = BS * 1;
+       // The occlusion search of 'isOccluded()' must stop short of the target
+       // point by distance 'endoff' (end offset) to not enter the target mapblock.
+       // For the 8 mapblock corners 'endoff' must therefore be the maximum diagonal
+       // of a mapblock, because we must consider all view angles.
+       // sqrt(1^2 + 1^2 + 1^2) = 1.732
+       float endoff = -BS * MAP_BLOCKSIZE * 1.732050807569;
+       v3s16 spn = cam_pos_nodes;
+       s16 bs2 = MAP_BLOCKSIZE / 2 + 1;
+       // to reduce the likelihood of falsely occluded blocks
+       // require at least two solid blocks
+       // this is a HACK, we should think of a more precise algorithm
+       u32 needed_count = 2;
+
+       return (
+               // For the central point of the mapblock 'endoff' can be halved
+               isOccluded(spn, cpn,
+                       step, stepfac, startoff, endoff / 2.0f, needed_count) &&
+               isOccluded(spn, cpn + v3s16(bs2,bs2,bs2),
+                       step, stepfac, startoff, endoff, needed_count) &&
+               isOccluded(spn, cpn + v3s16(bs2,bs2,-bs2),
+                       step, stepfac, startoff, endoff, needed_count) &&
+               isOccluded(spn, cpn + v3s16(bs2,-bs2,bs2),
+                       step, stepfac, startoff, endoff, needed_count) &&
+               isOccluded(spn, cpn + v3s16(bs2,-bs2,-bs2),
+                       step, stepfac, startoff, endoff, needed_count) &&
+               isOccluded(spn, cpn + v3s16(-bs2,bs2,bs2),
+                       step, stepfac, startoff, endoff, needed_count) &&
+               isOccluded(spn, cpn + v3s16(-bs2,bs2,-bs2),
+                       step, stepfac, startoff, endoff, needed_count) &&
+               isOccluded(spn, cpn + v3s16(-bs2,-bs2,bs2),
+                       step, stepfac, startoff, endoff, needed_count) &&
+               isOccluded(spn, cpn + v3s16(-bs2,-bs2,-bs2),
+                       step, stepfac, startoff, endoff, needed_count));
+}
+
 /*
        ServerMap
 */
-ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
+ServerMap::ServerMap(const std::string &savedir, IGameDef *gamedef,
+               EmergeManager *emerge):
        Map(dout_server, gamedef),
        settings_mgr(g_settings, savedir + DIR_DELIM + "map_meta.txt"),
        m_emerge(emerge),
@@ -1866,6 +1378,24 @@ s16 ServerMap::getWaterLevel()
        return getMapgenParams()->water_level;
 }
 
+bool ServerMap::saoPositionOverLimit(const v3f &p)
+{
+       return getMapgenParams()->saoPosOverLimit(p);
+}
+
+bool ServerMap::blockpos_over_mapgen_limit(v3s16 p)
+{
+       const s16 mapgen_limit_bp = rangelim(
+               getMapgenParams()->mapgen_limit, 0, MAX_MAP_GENERATION_LIMIT) /
+               MAP_BLOCKSIZE;
+       return p.X < -mapgen_limit_bp ||
+               p.X >  mapgen_limit_bp ||
+               p.Y < -mapgen_limit_bp ||
+               p.Y >  mapgen_limit_bp ||
+               p.Z < -mapgen_limit_bp ||
+               p.Z >  mapgen_limit_bp;
+}
+
 bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
 {
        s16 csize = getMapgenParams()->chunksize;
@@ -1879,9 +1409,9 @@ bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
        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(full_bpmin) ||
-               blockpos_over_limit(full_bpmax))
+       // Do nothing if not inside mapgen limits (+-1 because of neighbors)
+       if (blockpos_over_mapgen_limit(full_bpmin) ||
+                       blockpos_over_mapgen_limit(full_bpmax))
                return false;
 
        data->seed = getSeed();
@@ -2048,25 +1578,14 @@ ServerMapSector *ServerMap::createSector(v2s16 p2d)
 #endif
 
        /*
-               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.
+               Do not create over max mapgen limit
        */
-       const u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
-               g_settings->getU16("map_generation_limit"));
-       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");
+       const s16 max_limit_bp = MAX_MAP_GENERATION_LIMIT / MAP_BLOCKSIZE;
+       if (p2d.X < -max_limit_bp ||
+                       p2d.X >  max_limit_bp ||
+                       p2d.Y < -max_limit_bp ||
+                       p2d.Y >  max_limit_bp)
+               throw InvalidPositionException("createSector(): pos. over max mapgen limit");
 
        /*
                Generate blank sector
@@ -2207,10 +1726,10 @@ MapBlock * ServerMap::createBlock(v3s16 p)
                        FUNCTION_NAME, p.X, p.Y, p.Z);
 
        /*
-               Do not create over-limit
+               Do not create over max mapgen limit
        */
-       if (blockpos_over_limit(p))
-               throw InvalidPositionException("createBlock(): pos. over limit");
+       if (blockpos_over_max_limit(p))
+               throw InvalidPositionException("createBlock(): pos. over max mapgen limit");
 
        v2s16 p2d(p.X, p.Z);
        s16 block_y = p.Y;
@@ -2324,9 +1843,6 @@ MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
        return block;
 }
 
-void ServerMap::prepareBlock(MapBlock *block) {
-}
-
 // N.B.  This requires no synchronization, since data will not be modified unless
 // the VoxelManipulator being updated belongs to the same thread.
 void ServerMap::updateVManip(v3s16 pos)
@@ -2433,7 +1949,7 @@ std::string ServerMap::getSectorDir(v2s16 pos, int layout)
        }
 }
 
-v2s16 ServerMap::getSectorPos(std::string dirname)
+v2s16 ServerMap::getSectorPos(const std::string &dirname)
 {
        unsigned int x = 0, y = 0;
        int r;
@@ -2463,7 +1979,7 @@ v2s16 ServerMap::getSectorPos(std::string dirname)
        return pos;
 }
 
-v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
+v3s16 ServerMap::getBlockPos(const std::string &sectordir, const std::string &blockfile)
 {
        v2s16 p2d = getSectorPos(sectordir);
 
@@ -2772,13 +2288,13 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
 }
 #endif
 
-Database *ServerMap::createDatabase(
+MapDatabase *ServerMap::createDatabase(
        const std::string &name,
        const std::string &savedir,
        Settings &conf)
 {
        if (name == "sqlite3")
-               return new Database_SQLite3(savedir);
+               return new MapDatabaseSQLite3(savedir);
        if (name == "dummy")
                return new Database_Dummy();
        #if USE_LEVELDB
@@ -2790,8 +2306,11 @@ Database *ServerMap::createDatabase(
                return new Database_Redis(conf);
        #endif
        #if USE_POSTGRESQL
-       else if (name == "postgresql")
-               return new Database_PostgreSQL(conf);
+       else if (name == "postgresql") {
+               std::string connect_string = "";
+               conf.getNoEx("pgsql_connection", connect_string);
+               return new MapDatabasePostgreSQL(connect_string);
+       }
        #endif
        else
                throw BaseException(std::string("Database backend ") + name + " not supported.");
@@ -2812,7 +2331,7 @@ bool ServerMap::saveBlock(MapBlock *block)
        return saveBlock(block, dbase);
 }
 
-bool ServerMap::saveBlock(MapBlock *block, Database *db)
+bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db)
 {
        v3s16 p3d = block->getPos();
 
@@ -2843,16 +2362,15 @@ bool ServerMap::saveBlock(MapBlock *block, Database *db)
        return ret;
 }
 
-void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
+void ServerMap::loadBlock(const std::string &sectordir, const std::string &blockfile,
                MapSector *sector, bool save_after_load)
 {
        DSTACK(FUNCTION_NAME);
 
        std::string fullpath = sectordir + DIR_DELIM + blockfile;
        try {
-
                std::ifstream is(fullpath.c_str(), std::ios_base::binary);
-               if(is.good() == false)
+               if (!is.good())
                        throw FileNotGoodException("Cannot open block file");
 
                v3s16 p3d = getBlockPos(sectordir, blockfile);
@@ -2937,13 +2455,6 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
                        throw SerializationError("ServerMap::loadBlock(): Failed"
                                        " to read MapBlock version");
 
-               /*u32 block_size = MapBlock::serializedLength(version);
-               SharedBuffer<u8> data(block_size);
-               is.read((char*)*data, block_size);*/
-
-               // This will always return a sector because we're the server
-               //MapSector *sector = emergeSector(p2d);
-
                MapBlock *block = NULL;
                bool created_new = false;
                block = sector->getBlockNoCreateNoEx(p3d.Y);
@@ -3095,6 +2606,16 @@ void ServerMap::PrintInfo(std::ostream &out)
        out<<"ServerMap: ";
 }
 
+bool ServerMap::repairBlockLight(v3s16 blockpos,
+       std::map<v3s16, MapBlock *> *modified_blocks)
+{
+       MapBlock *block = emergeBlock(blockpos, false);
+       if (!block || !block->isGenerated())
+               return false;
+       voxalgo::repair_block_light(this, block, modified_blocks);
+       return true;
+}
+
 MMVManip::MMVManip(Map *map):
                VoxelManipulator(),
                m_is_dirty(false),
@@ -3161,7 +2682,7 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
                if(block_data_inexistent)
                {
 
-                       if (load_if_inexistent) {
+                       if (load_if_inexistent && !blockpos_over_max_limit(p)) {
                                ServerMap *svrmap = (ServerMap *)m_map;
                                block = svrmap->emergeBlock(p, false);
                                if (block == NULL)