Move MapBlock (de)serializing code out of Database class
[oweals/minetest.git] / src / map.cpp
index f128aff6c99d863f57069cf06d97ec4daa67d906..fda4d461dbe43480e674970849ba555b86ef39dc 100644 (file)
@@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "voxel.h"
 #include "porting.h"
-#include "mapgen.h"
+#include "serialization.h"
 #include "nodemetadata.h"
 #include "settings.h"
 #include "log.h"
@@ -32,10 +32,23 @@ 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 "rollback_interface.h"
+#include "environment.h"
 #include "emerge.h"
 #include "mapgen_v6.h"
-#include "mapgen_indev.h"
+#include "biome.h"
+#include "config.h"
+#include "server.h"
+#include "database.h"
+#include "database-dummy.h"
+#include "database-sqlite3.h"
+#if USE_LEVELDB
+#include "database-leveldb.h"
+#endif
+#if USE_REDIS
+#include "database-redis.h"
+#endif
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
@@ -65,8 +78,6 @@ Map::Map(std::ostream &dout, IGameDef *gamedef):
        m_gamedef(gamedef),
        m_sector_cache(NULL)
 {
-       /*m_sector_mutex.Init();
-       assert(m_sector_mutex.IsInitialized());*/
 }
 
 Map::~Map()
@@ -921,7 +932,8 @@ void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
 /*
 */
 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
-               std::map<v3s16, MapBlock*> &modified_blocks)
+               std::map<v3s16, MapBlock*> &modified_blocks,
+               bool remove_metadata)
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
@@ -1008,8 +1020,9 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        /*
                Remove node metadata
        */
-
-       removeNodeMetadata(p);
+       if (remove_metadata) {
+               removeNodeMetadata(p);
+       }
 
        /*
                Set the node on the map
@@ -1307,17 +1320,17 @@ void Map::removeNodeAndUpdate(v3s16 p,
        }
 }
 
-bool Map::addNodeWithEvent(v3s16 p, MapNode n)
+bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
 {
        MapEditEvent event;
-       event.type = MEET_ADDNODE;
+       event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
        event.p = p;
        event.n = n;
 
        bool succeeded = true;
        try{
                std::map<v3s16, MapBlock*> modified_blocks;
-               addNodeAndUpdate(p, n, modified_blocks);
+               addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
 
                // Copy modified_blocks to event
                for(std::map<v3s16, MapBlock*>::iterator
@@ -1460,11 +1473,11 @@ void Map::timerUpdate(float dtime, float unload_timeout,
                                v3s16 p = block->getPos();
 
                                // Save if modified
-                               if(block->getModified() != MOD_STATE_CLEAN
-                                               && save_before_unloading)
+                               if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading)
                                {
                                        modprofiler.add(block->getModifiedReason(), 1);
-                                       saveBlock(block);
+                                       if (!saveBlock(block))
+                                               continue;
                                        saved_blocks_count++;
                                }
 
@@ -1604,7 +1617,6 @@ struct NodeNeighbor {
        NeighborType t;
        v3s16 p;
        bool l; //can liquid
-       bool i; //infinity
 };
 
 void Map::transforming_liquid_add(v3s16 p) {
@@ -1615,376 +1627,8 @@ s32 Map::transforming_liquid_size() {
         return m_transforming_liquid.size();
 }
 
-const v3s16 g_7dirs[7] =
-{
-       // +right, +top, +back
-       v3s16( 0,-1, 0), // bottom
-       v3s16( 0, 0, 0), // self
-       v3s16( 0, 0, 1), // back
-       v3s16( 0, 0,-1), // front
-       v3s16( 1, 0, 0), // right
-       v3s16(-1, 0, 0), // left
-       v3s16( 0, 1, 0)  // top
-};
-
-#define D_BOTTOM 0
-#define D_TOP 6
-#define D_SELF 1
-
-void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
-{
-       INodeDefManager *nodemgr = m_gamedef->ndef();
-
-       DSTACK(__FUNCTION_NAME);
-       //TimeTaker timer("transformLiquids()");
-
-       u32 loopcount = 0;
-       u32 initial_size = m_transforming_liquid.size();
-
-       u8 relax = g_settings->getS16("liquid_relax");
-       bool fast_flood = g_settings->getS16("liquid_fast_flood");
-       int water_level = g_settings->getS16("water_level");
-
-       // list of nodes that due to viscosity have not reached their max level height
-       UniqueQueue<v3s16> must_reflow, must_reflow_second;
-
-       // List of MapBlocks that will require a lighting update (due to lava)
-       std::map<v3s16, MapBlock*> lighting_modified_blocks;
-
-       u16 loop_max = g_settings->getU16("liquid_loop_max");
-
-       //if (m_transforming_liquid.size() > 0) errorstream << "Liquid queue size="<<m_transforming_liquid.size()<<std::endl;
-
-       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)
-                       break;
-               loopcount++;
-               /*
-                       Get a queued transforming liquid node
-               */
-               v3s16 p0 = m_transforming_liquid.pop_front();
-               u16 total_level = 0;
-               // surrounding flowing liquid nodes
-               NodeNeighbor neighbors[7]; 
-               // current level of every block
-               s8 liquid_levels[7] = {-1, -1, -1, -1, -1, -1, -1};
-                // target levels
-               s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1};
-               s8 can_liquid_same_level = 0;
-               content_t liquid_kind = CONTENT_IGNORE;
-               content_t liquid_kind_flowing = CONTENT_IGNORE;
-               /*
-                       Collect information about the environment
-                */
-               const v3s16 *dirs = g_7dirs;
-               for (u16 i = 0; i < 7; i++) {
-                       NeighborType nt = NEIGHBOR_SAME_LEVEL;
-                       switch (i) {
-                               case D_TOP:
-                                       nt = NEIGHBOR_UPPER;
-                                       break;
-                               case D_BOTTOM:
-                                       nt = NEIGHBOR_LOWER;
-                                       break;
-                       }
-                       v3s16 npos = p0 + dirs[i];
-
-                       neighbors[i].n = getNodeNoEx(npos);
-                       neighbors[i].t = nt;
-                       neighbors[i].p = npos;
-                       neighbors[i].l = 0;
-                       neighbors[i].i = 0;
-                       NodeNeighbor & nb = neighbors[i];
-
-                       switch (nodemgr->get(nb.n.getContent()).liquid_type) {
-                               case LIQUID_NONE:
-                                       if (nb.n.getContent() == CONTENT_AIR) {
-                                               liquid_levels[i] = 0;
-                                               nb.l = 1;
-                                       }
-                                       break;
-                               case LIQUID_SOURCE:
-                                       // if this node is not (yet) of a liquid type,
-                                       // choose the first liquid type we encounter
-                                       if (liquid_kind_flowing == CONTENT_IGNORE)
-                                               liquid_kind_flowing = nodemgr->getId(
-                                                       nodemgr->get(nb.n).liquid_alternative_flowing);
-                                       if (liquid_kind == CONTENT_IGNORE)
-                                               liquid_kind = nb.n.getContent();
-                                       if (nb.n.getContent() == liquid_kind) {
-                                               liquid_levels[i] = LIQUID_LEVEL_SOURCE;
-                                               nb.l = 1;
-                                               nb.i = (nb.n.param2 & LIQUID_INFINITY_MASK);
-                                       }
-                                       break;
-                               case LIQUID_FLOWING:
-                                       // if this node is not (yet) of a liquid type,
-                                       // choose the first liquid type we encounter
-                                       if (liquid_kind_flowing == CONTENT_IGNORE)
-                                               liquid_kind_flowing = nb.n.getContent();
-                                       if (liquid_kind == CONTENT_IGNORE)
-                                               liquid_kind = nodemgr->getId(
-                                                       nodemgr->get(nb.n).liquid_alternative_source);
-                                       if (nb.n.getContent() == liquid_kind_flowing) {
-                                               liquid_levels[i] = (nb.n.param2 & LIQUID_LEVEL_MASK);
-                                               nb.l = 1;
-                                       }
-                                       break;
-                       }
-                       
-                       if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL)
-                               ++can_liquid_same_level;
-                       if (liquid_levels[i] > 0)
-                               total_level += liquid_levels[i];
-
-                       /*
-                       infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c="
-                       << nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1="
-                       << (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt="
-                       << nodemgr->get(nb.n.getContent()).liquid_type
-                       //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing
-                       << " l="<< nb.l << " inf="<< nb.i << " nlevel=" << (int)liquid_levels[i]
-                       << " tlevel=" << (int)total_level << " cansame="
-                       << (int)can_liquid_same_level << std::endl;
-                       */
-               }
-
-               if (liquid_kind == CONTENT_IGNORE ||
-                       !neighbors[D_SELF].l ||
-                       total_level <= 0)
-                       continue;
-
-               // fill bottom block
-               if (neighbors[D_BOTTOM].l) {
-                       liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ?
-                               LIQUID_LEVEL_SOURCE : total_level;
-                       total_level -= liquid_levels_want[D_BOTTOM];
-               }
-
-               //relax up
-               if (relax && ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) && liquid_levels[D_TOP] == 0 &&
-                       liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE &&
-                       total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level-
-                       (can_liquid_same_level - relax) &&
-                       can_liquid_same_level >= relax + 1) { 
-                       total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level; 
-               }
-
-               // prevent lakes in air above unloaded blocks
-               if (liquid_levels[D_TOP] == 0 && (p0.Y > water_level) && neighbors[D_BOTTOM].n.getContent() == CONTENT_IGNORE && !(loopcount % 3)) {
-                       --total_level;
-               }
-
-               // calculate self level 5 blocks
-               u8 want_level = 
-                         total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level
-                       ? LIQUID_LEVEL_SOURCE 
-                       : total_level / can_liquid_same_level;
-               total_level -= want_level * can_liquid_same_level;
-
-               //relax down
-               if (relax && p0.Y == water_level + 1 && liquid_levels[D_TOP] == 0 &&
-                       liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 &&
-                       total_level <= (can_liquid_same_level - relax) &&
-                       can_liquid_same_level >= relax + 1) {
-                       total_level = 0;
-               }
-
-               for (u16 ii = D_SELF; ii < D_TOP; ++ii) { // fill only same level
-                       if (!neighbors[ii].l)
-                               continue;
-                       liquid_levels_want[ii] = want_level;
-                       if (liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE && total_level > 0) {
-                               if (loopcount % 3 || liquid_levels[ii] <= 0){
-                                       if (liquid_levels[ii] > liquid_levels_want[ii]) {
-                                               ++liquid_levels_want[ii];
-                                               --total_level;
-                                       }
-                               } else if (neighbors[ii].l > 0){
-                                               ++liquid_levels_want[ii];
-                                               --total_level;
-                               }
-                       }
-               }
-
-               for (u16 ii = 0; ii < 7; ++ii) {
-                       if (total_level < 1) break;
-                       if (liquid_levels_want[ii] >= 0 &&
-                               liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE) {
-                               ++liquid_levels_want[ii];
-                               --total_level;
-                       }
-               }
-
-               // fill top block if can
-               if (neighbors[D_TOP].l) {
-                       liquid_levels_want[D_TOP] = total_level > LIQUID_LEVEL_SOURCE ?
-                               LIQUID_LEVEL_SOURCE : total_level;
-                       total_level -= liquid_levels_want[D_TOP];
-               }
-
-               for (u16 ii = 0; ii < 7; ii++) // infinity and cave flood optimization
-                       if (    neighbors[ii].i ||
-                               (liquid_levels_want[ii] >= 0 &&
-                                (fast_flood && p0.Y < water_level &&
-                                 (initial_size >= 1000
-                                  && ii != D_TOP
-                                  && want_level >= LIQUID_LEVEL_SOURCE/4
-                                  && can_liquid_same_level >= 5
-                                  && liquid_levels[D_TOP] >= LIQUID_LEVEL_SOURCE))))
-                               liquid_levels_want[ii] = LIQUID_LEVEL_SOURCE;
-
-               /*
-               if (total_level > 0) //|| flowed != volume)
-                       infostream <<" AFTER level=" << (int)total_level 
-                       //<< " flowed="<<flowed<< " volume=" << volume
-                       << " wantsame="<<(int)want_level<< " top="
-                       << (int)liquid_levels_want[D_TOP]<< " topwas="
-                       << (int)liquid_levels[D_TOP]<< " bot="
-                       << (int)liquid_levels_want[D_BOTTOM]<<std::endl;
-               */
-
-               u8 changed = 0;
-               for (u16 i = 0; i < 7; i++) {
-                       if (liquid_levels_want[i] < 0 || !neighbors[i].l) 
-                               continue;
-                       MapNode & n0 = neighbors[i].n;
-                       p0 = neighbors[i].p;
-                       /*
-                               decide on the type (and possibly level) of the current node
-                       */
-                       content_t new_node_content;
-                       s8 new_node_level = -1;
-                       u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
-                       if (viscosity > 1 && liquid_levels_want[i] != liquid_levels[i]) {
-                               // amount to gain, limited by viscosity
-                               // must be at least 1 in absolute value
-                               s8 level_inc = liquid_levels_want[i] - liquid_levels[i];
-                               if (level_inc < -viscosity || level_inc > viscosity)
-                                       new_node_level = liquid_levels[i] + level_inc/viscosity;
-                               else if (level_inc < 0)
-                                       new_node_level = liquid_levels[i] - 1;
-                               else if (level_inc > 0)
-                                       new_node_level = liquid_levels[i] + 1;
-                       } else {
-                               new_node_level = liquid_levels_want[i];
-                       }
-                       
-                       if (new_node_level >= LIQUID_LEVEL_SOURCE)
-                               new_node_content = liquid_kind;
-                       else if (new_node_level > 0)
-                               new_node_content = liquid_kind_flowing;
-                       else
-                               new_node_content = CONTENT_AIR;
-
-                       // last level must flow down on stairs
-                       if (liquid_levels_want[i] != liquid_levels[i] &&
-                               liquid_levels[D_TOP] <= 0 && !neighbors[D_BOTTOM].l &&
-                               new_node_level >= 1 && new_node_level <= 2) {
-                               for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
-                                       if (neighbors[ii].l)
-                                               must_reflow_second.push_back(p0 + dirs[ii]);
-                               }
-                       }
-
-                       /*
-                               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
-                                ))
-                               &&
-                                (nodemgr->get(n0.getContent()).liquid_type != LIQUID_SOURCE ||
-                                (((n0.param2 & LIQUID_INFINITY_MASK) ==
-                                       LIQUID_INFINITY_MASK) == neighbors[i].i
-                                ))
-                          ) {
-                               continue;
-                       }
-                       ++changed;
-
-                       /*
-                               update the current node
-                        */
-                       if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
-                               // set level to last 3 bits, flowing down bit to 4th bit
-                               n0.param2 = (new_node_level & LIQUID_LEVEL_MASK);
-                       } else if (nodemgr->get(new_node_content).liquid_type == LIQUID_SOURCE) {
-                               //n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
-                               n0.param2 = (neighbors[i].i ? LIQUID_INFINITY_MASK : 0x00);
-                       }
-                       /*
-                       infostream << "set node i=" <<(int)i<<" "<< PP(p0)<< " nc="
-                       <<new_node_content<< " p2="<<(int)n0.param2<< " nl="
-                       <<(int)new_node_level<<std::endl;
-                       */
-                       
-                       n0.setContent(new_node_content);
-                       // Find out whether there is a suspect for this action
-                       std::string suspect;
-                       if(m_gamedef->rollback()){
-                               suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
-                       }
-
-                       if(!suspect.empty()){
-                               // Blame suspect
-                               RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
-                               // Get old node for rollback
-                               RollbackNode rollback_oldnode(this, p0, m_gamedef);
-                               // Set node
-                               setNode(p0, n0);
-                               // Report
-                               RollbackNode rollback_newnode(this, p0, m_gamedef);
-                               RollbackAction action;
-                               action.setSetNode(p0, rollback_oldnode, rollback_newnode);
-                               m_gamedef->rollback()->reportAction(action);
-                       } else {
-                               // Set node
-                               setNode(p0, n0);
-                       }
-
-                       v3s16 blockpos = getNodeBlockPos(p0);
-                       MapBlock *block = getBlockNoCreateNoEx(blockpos);
-                       if(block != NULL) {
-                               modified_blocks[blockpos] = block;
-                               // If node emits light, MapBlock requires lighting update
-                               if(nodemgr->get(n0).light_source != 0)
-                                       lighting_modified_blocks[block->getPos()] = block;
-                       }
-                       must_reflow.push_back(neighbors[i].p);
-               }
-               /* //for better relax  only same level
-               if (changed)  for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) {
-                       if (!neighbors[ii].l) continue;
-                       must_reflow.push_back(p0 + dirs[ii]);
-               }*/
-       }
-       /*
-       if (loopcount)
-               infostream<<"Map::transformLiquids(): loopcount="<<loopcount
-               <<" reflow="<<must_reflow.size()
-               <<" queue="<< m_transforming_liquid.size()<<std::endl;
-       */
-       while (must_reflow.size() > 0)
-               m_transforming_liquid.push_back(must_reflow.pop_front());
-       while (must_reflow_second.size() > 0)
-               m_transforming_liquid.push_back(must_reflow_second.pop_front());
-       updateLighting(lighting_modified_blocks, modified_blocks);
-}
-
 void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
 {
-
-       if (g_settings->getBool("liquid_finite"))
-               return Map::transformLiquidsFinite(modified_blocks);
-
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
        DSTACK(__FUNCTION_NAME);
@@ -2117,6 +1761,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                content_t new_node_content;
                s8 new_node_level = -1;
                s8 max_node_level = -1;
+               u8 range = rangelim(nodemgr->get(liquid_kind).liquid_range, 0, LIQUID_LEVEL_MAX+1);
                if ((num_sources >= 2 && nodemgr->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
@@ -2126,6 +1771,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                        // 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;
                } else {
                        // no surrounding sources, so get the maximum level that can flow into this node
                        for (u16 i = 0; i < num_flows; i++) {
@@ -2166,7 +1813,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                        } else
                                new_node_level = max_node_level;
 
-                       if (new_node_level >= 0)
+                       if (max_node_level >= (LIQUID_LEVEL_MAX+1-range))
                                new_node_content = liquid_kind;
                        else
                                new_node_content = CONTENT_AIR;
@@ -2186,6 +1833,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                /*
                        update the current node
                 */
+               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) {
                        // set level to last 3 bits, flowing down bit to 4th bit
@@ -2223,8 +1871,9 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
                MapBlock *block = getBlockNoCreateNoEx(blockpos);
                if(block != NULL) {
                        modified_blocks[blockpos] =  block;
-                       // If node emits light, MapBlock requires lighting update
-                       if(nodemgr->get(n0).light_source != 0)
+                       // 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;
                }
 
@@ -2255,7 +1904,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
        updateLighting(lighting_modified_blocks, modified_blocks);
 }
 
-NodeMetadataMap::getNodeMetadata(v3s16 p)
+NodeMetadata *Map::getNodeMetadata(v3s16 p)
 {
        v3s16 blockpos = getNodeBlockPos(p);
        v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
@@ -2265,8 +1914,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
                                <<std::endl;
                return NULL;
@@ -2275,7 +1923,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p)
        return meta;
 }
 
-void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
+bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
 {
        v3s16 blockpos = getNodeBlockPos(p);
        v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
@@ -2285,13 +1933,13 @@ void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
                                <<std::endl;
-               return;
+               return false;
        }
        block->m_node_metadata.set(p_rel, meta);
+       return true;
 }
 
 void Map::removeNodeMetadata(v3s16 p)
@@ -2318,8 +1966,7 @@ NodeTimer Map::getNodeTimer(v3s16 p)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::getNodeTimer(): Block not found"
                                <<std::endl;
                return NodeTimer();
@@ -2338,8 +1985,7 @@ void Map::setNodeTimer(v3s16 p, NodeTimer t)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::setNodeTimer(): Block not found"
                                <<std::endl;
                return;
@@ -2366,41 +2012,41 @@ void Map::removeNodeTimer(v3s16 p)
 */
 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
        Map(dout_server, gamedef),
-       m_seed(0),
-       m_map_metadata_changed(true),
-       m_database(NULL),
-       m_database_read(NULL),
-       m_database_write(NULL)
+       m_emerge(emerge),
+       m_map_metadata_changed(true)
 {
        verbosestream<<__FUNCTION_NAME<<std::endl;
 
-       m_emerge = emerge;
-       m_mgparams = m_emerge->getParamsFromSettings(g_settings);
-       if (!m_mgparams)
-               m_mgparams = new MapgenV6Params();
-
-       m_seed = m_mgparams->seed;
-
-       if (g_settings->get("fixed_map_seed").empty())
-       {
-               m_seed = (((u64)(myrand() & 0xffff) << 0)
-                               | ((u64)(myrand() & 0xffff) << 16)
-                               | ((u64)(myrand() & 0xffff) << 32)
-                               | ((u64)(myrand() & 0xffff) << 48));
-               m_mgparams->seed = m_seed;
-       }
-
        /*
-               Experimental and debug stuff
+               Try to load map; if not found, create a new one.
        */
 
-       {
+       // Determine which database backend to use
+       std::string conf_path = savedir + DIR_DELIM + "world.mt";
+       Settings conf;
+       bool succeeded = conf.readConfigFile(conf_path.c_str());
+       if (!succeeded || !conf.exists("backend")) {
+               // fall back to sqlite3
+               dbase = new Database_SQLite3(this, savedir);
+               conf.set("backend", "sqlite3");
+       } else {
+               std::string backend = conf.get("backend");
+               if (backend == "dummy")
+                       dbase = new Database_Dummy(this);
+               else if (backend == "sqlite3")
+                       dbase = new Database_SQLite3(this, savedir);
+               #if USE_LEVELDB
+               else if (backend == "leveldb")
+                       dbase = new Database_LevelDB(this, savedir);
+               #endif
+               #if USE_REDIS
+               else if (backend == "redis")
+                       dbase = new Database_Redis(this, savedir);
+               #endif
+               else
+                       throw BaseException("Unknown map backend");
        }
 
-       /*
-               Try to load map; if not found, create a new one.
-       */
-
        m_savedir = savedir;
        m_map_saving_enabled = false;
 
@@ -2436,7 +2082,7 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer
                                infostream<<"ServerMap: Successfully loaded map "
                                                <<"metadata from "<<savedir
                                                <<", assuming valid save directory."
-                                               <<" seed="<<m_seed<<"."
+                                               <<" seed="<< m_emerge->params.seed <<"."
                                                <<std::endl;
 
                                m_map_saving_enabled = true;
@@ -2492,12 +2138,7 @@ ServerMap::~ServerMap()
        /*
                Close database if it was opened
        */
-       if(m_database_read)
-               sqlite3_finalize(m_database_read);
-       if(m_database_write)
-               sqlite3_finalize(m_database_write);
-       if(m_database)
-               sqlite3_close(m_database);
+       delete dbase;
 
 #if 0
        /*
@@ -2510,8 +2151,16 @@ ServerMap::~ServerMap()
                delete chunk;
        }
 #endif
+}
 
-       delete m_mgparams;
+u64 ServerMap::getSeed()
+{
+       return m_emerge->params.seed;
+}
+
+s16 ServerMap::getWaterLevel()
+{
+       return m_emerge->params.water_level;
 }
 
 bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
@@ -2519,7 +2168,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
        bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
        EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
 
-       s16 chunksize = m_mgparams->chunksize;
+       s16 chunksize = m_emerge->params.chunksize;
        s16 coffset = -chunksize / 2;
        v3s16 chunk_offset(coffset, coffset, coffset);
        v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
@@ -2535,7 +2184,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
                blockpos_over_limit(blockpos_max + extra_borders))
                return false;
 
-       data->seed = m_seed;
+       data->seed = m_emerge->params.seed;
        data->blockpos_min = blockpos_min;
        data->blockpos_max = blockpos_max;
        data->blockpos_requested = blockpos;
@@ -2556,6 +2205,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
                        // Sector metadata is loaded from disk if not already loaded.
                        ServerMapSector *sector = createSector(sectorpos);
                        assert(sector);
+                       (void) sector;
 
                        for(s16 y=blockpos_min.Y-extra_borders.Y;
                                        y<=blockpos_max.Y+extra_borders.Y; y++)
@@ -2605,7 +2255,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
                //TimeTaker timer("initBlockMake() initialEmerge");
                data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max, false);
        }
-       
+
        // 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++) {
@@ -2625,7 +2275,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
        return true;
 }
 
-MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
+void ServerMap::finishBlockMake(BlockMakeData *data,
                std::map<v3s16, MapBlock*> &changed_blocks)
 {
        v3s16 blockpos_min = data->blockpos_min;
@@ -2662,7 +2312,7 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
        {
                // 70ms @cs=8
                //TimeTaker timer("finishBlockMake() blitBackAll");
-               data->vmanip->blitBackAll(&changed_blocks);
+               data->vmanip->blitBackAll(&changed_blocks, false);
        }
 
        EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
@@ -2719,7 +2369,9 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
                                y<=blockpos_max.Y+extra_borders.Y; y++)
                {
                        v3s16 p(x, y, z);
-                       getBlockNoCreateNoEx(p)->setLightingExpired(false);
+                       MapBlock * block = getBlockNoCreateNoEx(p);
+                       if (block != NULL)
+                               block->setLightingExpired(false);
                }
 
 #if 0
@@ -2735,7 +2387,8 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
                        i != changed_blocks.end(); ++i)
        {
                MapBlock *block = i->second;
-               assert(block);
+               if (!block)
+                       continue;
                /*
                        Update day/night difference cache of the MapBlocks
                */
@@ -2756,7 +2409,8 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
        {
                v3s16 p(x, y, z);
                MapBlock *block = getBlockNoCreateNoEx(p);
-               assert(block);
+               if (!block)
+                       continue;
                block->setGenerated(true);
        }
 
@@ -2769,6 +2423,8 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
        /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
                        <<","<<blockpos_requested.Y<<","
                        <<blockpos_requested.Z<<")"<<std::endl;*/
+
+
 #if 0
        if(enable_mapgen_debug_info)
        {
@@ -2792,10 +2448,7 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
        }
 #endif
 
-       MapBlock *block = getBlockNoCreateNoEx(blockpos_requested);
-       assert(block);
-
-       return block;
+       getBlockNoCreateNoEx(blockpos_requested);
 }
 
 ServerMapSector * ServerMap::createSector(v2s16 p2d)
@@ -3061,7 +2714,9 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
 
                return block;
        }
-       /*if(allow_generate)
+
+#if 0
+       if(allow_generate)
        {
                std::map<v3s16, MapBlock*> modified_blocks;
                MapBlock *block = generateBlock(p, modified_blocks);
@@ -3084,11 +2739,24 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
 
                        return block;
                }
-       }*/
+       }
+#endif
 
        return NULL;
 }
 
+MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
+{
+       MapBlock *block = getBlockNoCreateNoEx(p3d);
+       if (block == NULL)
+               m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
+
+       return block;
+}
+
+void ServerMap::prepareBlock(MapBlock *block) {
+}
+
 s16 ServerMap::findGroundLevel(v2s16 p2d)
 {
 #if 0
@@ -3133,81 +2801,12 @@ plan_b:
        //return (s16)level;
 }
 
-void ServerMap::createDatabase() {
-       int e;
-       assert(m_database);
-       e = sqlite3_exec(m_database,
-               "CREATE TABLE IF NOT EXISTS `blocks` ("
-                       "`pos` INT NOT NULL PRIMARY KEY,"
-                       "`data` BLOB"
-               ");"
-       , NULL, NULL, NULL);
-       if(e == SQLITE_ABORT)
-               throw FileNotGoodException("Could not create database structure");
-       else
-               infostream<<"ServerMap: Database structure was created";
-}
-
-void ServerMap::verifyDatabase() {
-       if(m_database)
-               return;
-
-       {
-               std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
-               bool needs_create = false;
-               int d;
-
-               /*
-                       Open the database connection
-               */
-
-               createDirs(m_savedir);
-
-               if(!fs::PathExists(dbp))
-                       needs_create = true;
-
-               d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
-               if(d != SQLITE_OK) {
-                       infostream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
-                       throw FileNotGoodException("Cannot open database file");
-               }
-
-               if(needs_create)
-                       createDatabase();
-
-               d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
-               if(d != SQLITE_OK) {
-                       infostream<<"WARNING: Database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
-                       throw FileNotGoodException("Cannot prepare read statement");
-               }
-
-               d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
-               if(d != SQLITE_OK) {
-                       infostream<<"WARNING: Database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
-                       throw FileNotGoodException("Cannot prepare write statement");
-               }
-
-               d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
-               if(d != SQLITE_OK) {
-                       infostream<<"WARNING: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
-                       throw FileNotGoodException("Cannot prepare read statement");
-               }
-
-               infostream<<"ServerMap: Database opened"<<std::endl;
-       }
-}
-
 bool ServerMap::loadFromFolders() {
-       if(!m_database && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
+       if(!dbase->Initialized() && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) // ?
                return true;
        return false;
 }
 
-sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
-       return (sqlite3_int64)pos.Z*16777216 +
-               (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
-}
-
 void ServerMap::createDirs(std::string path)
 {
        if(fs::CreateAllDirs(path) == false)
@@ -3237,12 +2836,13 @@ std::string ServerMap::getSectorDir(v2s16 pos, int layout)
                        return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
                default:
                        assert(false);
+                       return "";
        }
 }
 
 v2s16 ServerMap::getSectorPos(std::string dirname)
 {
-       unsigned int x, y;
+       unsigned int x = 0, y = 0;
        int r;
        std::string component;
        fs::RemoveLastPathComponent(dirname, &component, 1);
@@ -3380,50 +2980,13 @@ void ServerMap::save(ModifiedState save_level)
        }
 }
 
-static s32 unsignedToSigned(s32 i, s32 max_positive)
-{
-       if(i < max_positive)
-               return i;
-       else
-               return i - 2*max_positive;
-}
-
-// modulo of a negative number does not work consistently in C
-static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod)
-{
-       if(i >= 0)
-               return i % mod;
-       return mod - ((-i) % mod);
-}
-
-v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
-{
-       s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048);
-       i = (i - x) / 4096;
-       s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048);
-       i = (i - y) / 4096;
-       s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048);
-       return v3s16(x,y,z);
-}
-
 void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst)
 {
        if(loadFromFolders()){
                errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
                                <<"all blocks that are stored in flat files"<<std::endl;
        }
-
-       {
-               verifyDatabase();
-
-               while(sqlite3_step(m_database_list) == SQLITE_ROW)
-               {
-                       sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
-                       v3s16 p = getIntegerAsBlock(block_i);
-                       //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
-                       dst.push_back(p);
-               }
-       }
+       dbase->listAllLoadableBlocks(dst);
 }
 
 void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst)
@@ -3457,20 +3020,21 @@ void ServerMap::saveMapMeta()
        createDirs(m_savedir);
 
        std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
-       std::ofstream os(fullpath.c_str(), std::ios_base::binary);
-       if(os.good() == false)
-       {
-               infostream<<"ERROR: ServerMap::saveMapMeta(): "
-                               <<"could not open"<<fullpath<<std::endl;
-               throw FileNotGoodException("Cannot open chunk metadata");
-       }
+       std::ostringstream ss(std::ios_base::binary);
 
        Settings params;
 
-       m_emerge->setParamsToSettings(&params);
-       params.writeLines(os);
+       m_emerge->saveParamsToSettings(&params);
+       params.writeLines(ss);
 
-       os<<"[end_of_params]\n";
+       ss<<"[end_of_params]\n";
+
+       if(!fs::safeWriteToFile(fullpath, ss.str()))
+       {
+               infostream<<"ERROR: ServerMap::saveMapMeta(): "
+                               <<"could not write "<<fullpath<<std::endl;
+               throw FileNotGoodException("Cannot save chunk metadata");
+       }
 
        m_map_metadata_changed = false;
 }
@@ -3505,47 +3069,30 @@ void ServerMap::loadMapMeta()
                        break;
                params.parseConfigLine(line);
        }
-       
-       MapgenParams *mgparams;
-       try {
-               mgparams = m_emerge->getParamsFromSettings(&params);
-       } catch (SettingNotFoundException &e) {
-               infostream << "Couldn't get a setting from map_meta.txt: "
-                                  << e.what() << std::endl;
-               mgparams = NULL;
-       }
-       
-       if (mgparams) {
-               if (m_mgparams)
-                       delete m_mgparams;
-               m_mgparams = mgparams;
-               m_seed = mgparams->seed;
-       } else {
-               if (params.exists("seed")) {
-                       m_seed = params.getU64("seed");
-                       m_mgparams->seed = m_seed;
-               }
-       }
 
-       verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
+       m_emerge->loadParamsFromSettings(&params);
+
+       verbosestream<<"ServerMap::loadMapMeta(): seed="
+               << m_emerge->params.seed<<std::endl;
 }
 
 void ServerMap::saveSectorMeta(ServerMapSector *sector)
 {
        DSTACK(__FUNCTION_NAME);
        // Format used for writing
-       u8 version = SER_FMT_VER_HIGHEST;
+       u8 version = SER_FMT_VER_HIGHEST_WRITE;
        // Get destination
        v2s16 pos = sector->getPos();
        std::string dir = getSectorDir(pos);
        createDirs(dir);
 
        std::string fullpath = dir + DIR_DELIM + "meta";
-       std::ofstream o(fullpath.c_str(), std::ios_base::binary);
-       if(o.good() == false)
-               throw FileNotGoodException("Cannot open sector metafile");
+       std::ostringstream ss(std::ios_base::binary);
+
+       sector->serialize(ss, version);
 
-       sector->serialize(o, version);
+       if(!fs::safeWriteToFile(fullpath, ss.str()))
+               throw FileNotGoodException("Cannot write sector metafile");
 
        sector->differs_from_disk = false;
 }
@@ -3706,97 +3253,59 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
 }
 #endif
 
-void ServerMap::beginSave() {
-       verifyDatabase();
-       if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
-               infostream<<"WARNING: beginSave() failed, saving might be slow.";
+void ServerMap::beginSave()
+{
+       dbase->beginSave();
 }
 
-void ServerMap::endSave() {
-       verifyDatabase();
-       if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
-               infostream<<"WARNING: endSave() failed, map might not have saved.";
+void ServerMap::endSave()
+{
+       dbase->endSave();
 }
 
-void ServerMap::saveBlock(MapBlock *block)
+bool ServerMap::saveBlock(MapBlock *block)
 {
-       DSTACK(__FUNCTION_NAME);
-       /*
-               Dummy blocks are not written
-       */
-       if(block->isDummy())
-       {
-               /*v3s16 p = block->getPos();
-               infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
-                               <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-               return;
-       }
+       return saveBlock(block, dbase);
+}
 
-       // Format used for writing
-       u8 version = SER_FMT_VER_HIGHEST;
-       // Get destination
+bool ServerMap::saveBlock(MapBlock *block, Database *db)
+{
        v3s16 p3d = block->getPos();
 
+       // Dummy blocks are not written
+       if (block->isDummy()) {
+               errorstream << "WARNING: saveBlock: Not writing dummy block "
+                       << PP(p3d) << std::endl;
+               return true;
+       }
 
-#if 0
-       v2s16 p2d(p3d.X, p3d.Z);
-       std::string sectordir = getSectorDir(p2d);
-
-       createDirs(sectordir);
+       // Format used for writing
+       u8 version = SER_FMT_VER_HIGHEST_WRITE;
 
-       std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
-       std::ofstream o(fullpath.c_str(), std::ios_base::binary);
-       if(o.good() == false)
-               throw FileNotGoodException("Cannot open block data");
-#endif
        /*
                [0] u8 serialization version
                [1] data
        */
-
-       verifyDatabase();
-
        std::ostringstream o(std::ios_base::binary);
-
-       o.write((char*)&version, 1);
-
-       // Write basic data
+       o.write((char*) &version, 1);
        block->serialize(o, version, true);
 
-       // Write block to database
-
-       std::string tmp = o.str();
-       const char *bytes = tmp.c_str();
-
-       bool success = true;
-       if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) {
-               infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
-               success = false;
-       }
-       if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) { // TODO this mught not be the right length
-               infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
-               success = false;
-       }
-       int written = sqlite3_step(m_database_write);
-       if(written != SQLITE_DONE) {
-               errorstream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
-                               <<sqlite3_errmsg(m_database)<<std::endl;
-               success = false;
-       }
-       // Make ready for later reuse
-       sqlite3_reset(m_database_write);
-
-       // We just wrote it to the disk so clear modified flag
-       if (success)
+       std::string data = o.str();
+       bool ret = db->saveBlock(p3d, data);
+       if(ret) {
+               // We just wrote it to the disk so clear modified flag
                block->resetModified();
+       }
+       return ret;
 }
 
-void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
+void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
+               MapSector *sector, bool save_after_load)
 {
        DSTACK(__FUNCTION_NAME);
 
        std::string fullpath = sectordir+DIR_DELIM+blockfile;
-       try{
+       try {
 
                std::ifstream is(fullpath.c_str(), std::ios_base::binary);
                if(is.good() == false)
@@ -3841,7 +3350,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
                        Save blocks loaded in old format in new format
                */
 
-               if(version < SER_FMT_VER_HIGHEST || save_after_load)
+               if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
                {
                        saveBlock(block);
 
@@ -3860,7 +3369,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
                                <<" (SerializationError). "
                                <<"what()="<<e.what()
                                <<std::endl;
-                               //" Ignoring. A new one will be generated.
+                               // Ignoring. A new one will be generated.
                assert(0);
 
                // TODO: Backup file; name is in fullpath.
@@ -3908,7 +3417,7 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
                        Save blocks loaded in old format in new format
                */
 
-               //if(version < SER_FMT_VER_HIGHEST || save_after_load)
+               //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
                // Only save if asked to; no need to update version
                if(save_after_load)
                        saveBlock(block);
@@ -3942,38 +3451,14 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
 
        v2s16 p2d(blockpos.X, blockpos.Z);
 
-       if(!loadFromFolders()) {
-               verifyDatabase();
-
-               if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
-                       infostream<<"WARNING: Could not bind block position for load: "
-                               <<sqlite3_errmsg(m_database)<<std::endl;
-               if(sqlite3_step(m_database_read) == SQLITE_ROW) {
-                       /*
-                               Make sure sector is loaded
-                       */
-                       MapSector *sector = createSector(p2d);
-
-                       /*
-                               Load block
-                       */
-                       const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
-                       size_t len = sqlite3_column_bytes(m_database_read, 0);
-
-                       std::string datastr(data, len);
+       std::string ret;
 
-                       loadBlock(&datastr, blockpos, sector, false);
-
-                       sqlite3_step(m_database_read);
-                       // We should never get more than 1 row, so ok to reset
-                       sqlite3_reset(m_database_read);
-
-                       return getBlockNoCreateNoEx(blockpos);
-               }
-               sqlite3_reset(m_database_read);
-
-               // Not found in database, try the files
+       ret = dbase->loadBlock(blockpos);
+       if (ret != "") {
+               loadBlock(&ret, blockpos, createSector(p2d), false);
+               return getBlockNoCreateNoEx(blockpos);
        }
+       // Not found in database, try the files
 
        // The directory layout we're going to load from.
        //  1 - original sectors/xxxxzzzz/
@@ -4036,167 +3521,10 @@ void ServerMap::PrintInfo(std::ostream &out)
        out<<"ServerMap: ";
 }
 
-/*
-       MapVoxelManipulator
-*/
-
-MapVoxelManipulator::MapVoxelManipulator(Map *map)
-{
-       m_map = map;
-}
-
-MapVoxelManipulator::~MapVoxelManipulator()
-{
-       /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
-                       <<std::endl;*/
-}
-
-void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
-{
-       TimeTaker timer1("emerge", &emerge_time);
-
-       // Units of these are MapBlocks
-       v3s16 p_min = getNodeBlockPos(a.MinEdge);
-       v3s16 p_max = getNodeBlockPos(a.MaxEdge);
-
-       VoxelArea block_area_nodes
-                       (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
-
-       addArea(block_area_nodes);
-
-       for(s32 z=p_min.Z; z<=p_max.Z; z++)
-       for(s32 y=p_min.Y; y<=p_max.Y; y++)
-       for(s32 x=p_min.X; x<=p_max.X; x++)
-       {
-               u8 flags = 0;
-               MapBlock *block;
-               v3s16 p(x,y,z);
-               std::map<v3s16, u8>::iterator n;
-               n = m_loaded_blocks.find(p);
-               if(n != m_loaded_blocks.end())
-                       continue;
-
-               bool block_data_inexistent = false;
-               try
-               {
-                       TimeTaker timer1("emerge load", &emerge_load_time);
-
-                       /*infostream<<"Loading block (caller_id="<<caller_id<<")"
-                                       <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
-                                       <<" wanted area: ";
-                       a.print(infostream);
-                       infostream<<std::endl;*/
-
-                       block = m_map->getBlockNoCreate(p);
-                       if(block->isDummy())
-                               block_data_inexistent = true;
-                       else
-                               block->copyTo(*this);
-               }
-               catch(InvalidPositionException &e)
-               {
-                       block_data_inexistent = true;
-               }
-
-               if(block_data_inexistent)
-               {
-                       flags |= VMANIP_BLOCK_DATA_INEXIST;
-
-                       VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
-                       // Fill with VOXELFLAG_INEXISTENT
-                       for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
-                       for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
-                       {
-                               s32 i = m_area.index(a.MinEdge.X,y,z);
-                               memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
-                       }
-               }
-               /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
-               {
-                       // Mark that block was loaded as blank
-                       flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
-               }*/
-
-               m_loaded_blocks[p] = flags;
-       }
-
-       //infostream<<"emerge done"<<std::endl;
-}
-
-/*
-       SUGG: Add an option to only update eg. water and air nodes.
-             This will make it interfere less with important stuff if
-                 run on background.
-*/
-void MapVoxelManipulator::blitBack
-               (std::map<v3s16, MapBlock*> & modified_blocks)
-{
-       if(m_area.getExtent() == v3s16(0,0,0))
-               return;
-
-       //TimeTaker timer1("blitBack");
-
-       /*infostream<<"blitBack(): m_loaded_blocks.size()="
-                       <<m_loaded_blocks.size()<<std::endl;*/
-
-       /*
-               Initialize block cache
-       */
-       v3s16 blockpos_last;
-       MapBlock *block = NULL;
-       bool block_checked_in_modified = false;
-
-       for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
-       for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
-       for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
-       {
-               v3s16 p(x,y,z);
-
-               u8 f = m_flags[m_area.index(p)];
-               if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
-                       continue;
-
-               MapNode &n = m_data[m_area.index(p)];
-
-               v3s16 blockpos = getNodeBlockPos(p);
-
-               try
-               {
-                       // Get block
-                       if(block == NULL || blockpos != blockpos_last){
-                               block = m_map->getBlockNoCreate(blockpos);
-                               blockpos_last = blockpos;
-                               block_checked_in_modified = false;
-                       }
-
-                       // Calculate relative position in block
-                       v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
-
-                       // Don't continue if nothing has changed here
-                       if(block->getNode(relpos) == n)
-                               continue;
-
-                       //m_map->setNode(m_area.MinEdge + p, n);
-                       block->setNode(relpos, n);
-
-                       /*
-                               Make sure block is in modified_blocks
-                       */
-                       if(block_checked_in_modified == false)
-                       {
-                               modified_blocks[blockpos] = block;
-                               block_checked_in_modified = true;
-                       }
-               }
-               catch(InvalidPositionException &e)
-               {
-               }
-       }
-}
-
 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
-               MapVoxelManipulator(map),
-               m_create_area(false)
+               VoxelManipulator(),
+               m_create_area(false),
+               m_map(map)
 {
 }
 
@@ -4204,12 +3532,6 @@ ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
 {
 }
 
-void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
-{
-       // Just create the area so that it can be pointed to
-       VoxelManipulator::emerge(a, caller_id);
-}
-
 void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min,
                                                v3s16 blockpos_max, bool load_if_inexistent)
 {
@@ -4263,7 +3585,7 @@ void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min,
 
                if(block_data_inexistent)
                {
-                       
+
                        if (load_if_inexistent) {
                                ServerMap *svrmap = (ServerMap *)m_map;
                                block = svrmap->emergeBlock(p, false);
@@ -4273,17 +3595,17 @@ void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min,
                                        block->copyTo(*this);
                        } else {
                                flags |= VMANIP_BLOCK_DATA_INEXIST;
-                               
+
                                /*
                                        Mark area inexistent
                                */
                                VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
-                               // Fill with VOXELFLAG_INEXISTENT
+                               // Fill with VOXELFLAG_NO_DATA
                                for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
                                for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
                                {
                                        s32 i = m_area.index(a.MinEdge.X,y,z);
-                                       memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
+                                       memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
                                }
                        }
                }
@@ -4298,7 +3620,8 @@ void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min,
 }
 
 void ManualMapVoxelManipulator::blitBackAll(
-               std::map<v3s16, MapBlock*> * modified_blocks)
+               std::map<v3s16, MapBlock*> *modified_blocks,
+               bool overwrite_generated)
 {
        if(m_area.getExtent() == v3s16(0,0,0))
                return;
@@ -4313,10 +3636,9 @@ void ManualMapVoxelManipulator::blitBackAll(
                v3s16 p = i->first;
                MapBlock *block = m_map->getBlockNoCreateNoEx(p);
                bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
-               if(existed == false)
-               {
+               if ((existed == false) || (block == NULL) ||
+                       (overwrite_generated == false && block->isGenerated() == true))
                        continue;
-               }
 
                block->copyFrom(*this);