Move MapBlock (de)serializing code out of Database class
[oweals/minetest.git] / src / map.cpp
index 07af2676b45a104c617784f74ca689e35fc29dc0..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,9 +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 "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<<")"
 
@@ -64,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()
@@ -73,34 +85,30 @@ Map::~Map()
        /*
                Free all MapSectors
        */
-       core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
-       for(; i.atEnd() == false; i++)
+       for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
+               i != m_sectors.end(); ++i)
        {
-               MapSector *sector = i.getNode()->getValue();
-               delete sector;
+               delete i->second;
        }
 }
 
 void Map::addEventReceiver(MapEventReceiver *event_receiver)
 {
-       m_event_receivers.insert(event_receiver, false);
+       m_event_receivers.insert(event_receiver);
 }
 
 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
 {
-       if(m_event_receivers.find(event_receiver) == NULL)
-               return;
-       m_event_receivers.remove(event_receiver);
+       m_event_receivers.erase(event_receiver);
 }
 
 void Map::dispatchEvent(MapEditEvent *event)
 {
-       for(core::map<MapEventReceiver*, bool>::Iterator
-                       i = m_event_receivers.getIterator();
-                       i.atEnd()==false; i++)
+       for(std::set<MapEventReceiver*>::iterator
+                       i = m_event_receivers.begin();
+                       i != m_event_receivers.end(); ++i)
        {
-               MapEventReceiver* event_receiver = i.getNode()->getKey();
-               event_receiver->onMapEditEvent(event);
+               (*i)->onMapEditEvent(event);
        }
 }
 
@@ -111,12 +119,12 @@ MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
                return sector;
        }
 
-       core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
+       std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
 
-       if(n == NULL)
+       if(n == m_sectors.end())
                return NULL;
 
-       MapSector *sector = n->getValue();
+       MapSector *sector = n->second;
 
        // Cache the last result
        m_sector_cache_p = p;
@@ -236,9 +244,9 @@ void Map::setNode(v3s16 p, MapNode & n)
        values of from_nodes are lighting values.
 */
 void Map::unspreadLight(enum LightBank bank,
-               core::map<v3s16, u8> & from_nodes,
-               core::map<v3s16, bool> & light_sources,
-               core::map<v3s16, MapBlock*>  & modified_blocks)
+               std::map<v3s16, u8> & from_nodes,
+               std::set<v3s16> & light_sources,
+               std::map<v3s16, MapBlock*>  & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -256,9 +264,7 @@ void Map::unspreadLight(enum LightBank bank,
 
        u32 blockchangecount = 0;
 
-       core::map<v3s16, u8> unlighted_nodes;
-       core::map<v3s16, u8>::Iterator j;
-       j = from_nodes.getIterator();
+       std::map<v3s16, u8> unlighted_nodes;
 
        /*
                Initialize block cache
@@ -268,9 +274,10 @@ void Map::unspreadLight(enum LightBank bank,
        // Cache this a bit, too
        bool block_checked_in_modified = false;
 
-       for(; j.atEnd() == false; j++)
+       for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
+               j != from_nodes.end(); ++j)
        {
-               v3s16 pos = j.getNode()->getKey();
+               v3s16 pos = j->first;
                v3s16 blockpos = getNodeBlockPos(pos);
 
                // Only fetch a new block if the block position has changed
@@ -292,12 +299,12 @@ void Map::unspreadLight(enum LightBank bank,
                        continue;
 
                // Calculate relative position in block
-               v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
+               //v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
 
                // Get node straight from the block
-               MapNode n = block->getNode(relpos);
+               //MapNode n = block->getNode(relpos);
 
-               u8 oldlight = j.getNode()->getValue();
+               u8 oldlight = j->second;
 
                // Loop through 6 neighbors
                for(u16 i=0; i<6; i++)
@@ -354,7 +361,7 @@ void Map::unspreadLight(enum LightBank bank,
                                                n2.setLight(bank, 0, nodemgr);
                                                block->setNode(relpos, n2);
 
-                                               unlighted_nodes.insert(n2pos, current_light);
+                                               unlighted_nodes[n2pos] = current_light;
                                                changed = true;
 
                                                /*
@@ -373,16 +380,16 @@ void Map::unspreadLight(enum LightBank bank,
                                                light_sources.remove(n2pos);*/
                                }
                                else{
-                                       light_sources.insert(n2pos, true);
+                                       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) == NULL)
+                                       if(modified_blocks.find(blockpos) == modified_blocks.end())
                                        {
-                                               modified_blocks.insert(blockpos, block);
+                                               modified_blocks[blockpos] = block;
                                        }
                                        block_checked_in_modified = true;
                                }
@@ -408,11 +415,11 @@ void Map::unspreadLight(enum LightBank bank,
 */
 void Map::unLightNeighbors(enum LightBank bank,
                v3s16 pos, u8 lightwas,
-               core::map<v3s16, bool> & light_sources,
-               core::map<v3s16, MapBlock*>  & modified_blocks)
+               std::set<v3s16> & light_sources,
+               std::map<v3s16, MapBlock*>  & modified_blocks)
 {
-       core::map<v3s16, u8> from_nodes;
-       from_nodes.insert(pos, lightwas);
+       std::map<v3s16, u8> from_nodes;
+       from_nodes[pos] = lightwas;
 
        unspreadLight(bank, from_nodes, light_sources, modified_blocks);
 }
@@ -422,8 +429,8 @@ void Map::unLightNeighbors(enum LightBank bank,
        goes on recursively.
 */
 void Map::spreadLight(enum LightBank bank,
-               core::map<v3s16, bool> & from_nodes,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+               std::set<v3s16> & from_nodes,
+               std::map<v3s16, MapBlock*> & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -441,9 +448,7 @@ void Map::spreadLight(enum LightBank bank,
 
        u32 blockchangecount = 0;
 
-       core::map<v3s16, bool> lighted_nodes;
-       core::map<v3s16, bool>::Iterator j;
-       j = from_nodes.getIterator();
+       std::set<v3s16> lighted_nodes;
 
        /*
                Initialize block cache
@@ -453,12 +458,10 @@ void Map::spreadLight(enum LightBank bank,
        // Cache this a bit, too
        bool block_checked_in_modified = false;
 
-       for(; j.atEnd() == false; j++)
-       //for(; j != from_nodes.end(); j++)
+       for(std::set<v3s16>::iterator j = from_nodes.begin();
+               j != from_nodes.end(); ++j)
        {
-               v3s16 pos = j.getNode()->getKey();
-               //v3s16 pos = *j;
-               //infostream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
+               v3s16 pos = *j;
                v3s16 blockpos = getNodeBlockPos(pos);
 
                // Only fetch a new block if the block position has changed
@@ -525,8 +528,7 @@ void Map::spreadLight(enum LightBank bank,
                                */
                                if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
                                {
-                                       lighted_nodes.insert(n2pos, true);
-                                       //lighted_nodes.push_back(n2pos);
+                                       lighted_nodes.insert(n2pos);
                                        changed = true;
                                }
                                /*
@@ -539,8 +541,7 @@ void Map::spreadLight(enum LightBank bank,
                                        {
                                                n2.setLight(bank, newlight, nodemgr);
                                                block->setNode(relpos, n2);
-                                               lighted_nodes.insert(n2pos, true);
-                                               //lighted_nodes.push_back(n2pos);
+                                               lighted_nodes.insert(n2pos);
                                                changed = true;
                                        }
                                }
@@ -549,9 +550,9 @@ void Map::spreadLight(enum LightBank bank,
                                if(changed == true && block_checked_in_modified == false)
                                {
                                        // If the block is not found in modified_blocks, add.
-                                       if(modified_blocks.find(blockpos) == NULL)
+                                       if(modified_blocks.find(blockpos) == modified_blocks.end())
                                        {
-                                               modified_blocks.insert(blockpos, block);
+                                               modified_blocks[blockpos] = block;
                                        }
                                        block_checked_in_modified = true;
                                }
@@ -577,10 +578,10 @@ void Map::spreadLight(enum LightBank bank,
 */
 void Map::lightNeighbors(enum LightBank bank,
                v3s16 pos,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+               std::map<v3s16, MapBlock*> & modified_blocks)
 {
-       core::map<v3s16, bool> from_nodes;
-       from_nodes.insert(pos, true);
+       std::set<v3s16> from_nodes;
+       from_nodes.insert(pos);
        spreadLight(bank, from_nodes, modified_blocks);
 }
 
@@ -635,7 +636,7 @@ v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
        Mud is turned into grass in where the sunlight stops.
 */
 s16 Map::propagateSunlight(v3s16 start,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+               std::map<v3s16, MapBlock*> & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -662,7 +663,7 @@ s16 Map::propagateSunlight(v3s16 start,
                        n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
                        block->setNode(relpos, n);
 
-                       modified_blocks.insert(blockpos, block);
+                       modified_blocks[blockpos] = block;
                }
                else
                {
@@ -674,8 +675,8 @@ s16 Map::propagateSunlight(v3s16 start,
 }
 
 void Map::updateLighting(enum LightBank bank,
-               core::map<v3s16, MapBlock*> & a_blocks,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+               std::map<v3s16, MapBlock*> & a_blocks,
+               std::map<v3s16, MapBlock*> & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -688,22 +689,21 @@ void Map::updateLighting(enum LightBank bank,
        //bool debug=true;
        //u32 count_was = modified_blocks.size();
 
-       core::map<v3s16, MapBlock*> blocks_to_update;
+       std::map<v3s16, MapBlock*> blocks_to_update;
 
-       core::map<v3s16, bool> light_sources;
+       std::set<v3s16> light_sources;
 
-       core::map<v3s16, u8> unlight_from;
+       std::map<v3s16, u8> unlight_from;
 
        int num_bottom_invalid = 0;
 
        {
        //TimeTaker t("first stuff");
 
-       core::map<v3s16, MapBlock*>::Iterator i;
-       i = a_blocks.getIterator();
-       for(; i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator i = a_blocks.begin();
+               i != a_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
+               MapBlock *block = i->second;
 
                for(;;)
                {
@@ -713,9 +713,8 @@ void Map::updateLighting(enum LightBank bank,
 
                        v3s16 pos = block->getPos();
                        v3s16 posnodes = block->getPosRelative();
-                       modified_blocks.insert(pos, block);
-
-                       blocks_to_update.insert(pos, block);
+                       modified_blocks[pos] = block;
+                       blocks_to_update[pos] = block;
 
                        /*
                                Clear all light from block
@@ -735,7 +734,7 @@ void Map::updateLighting(enum LightBank bank,
                                        // If node sources light, add to list
                                        u8 source = nodemgr->get(n).light_source;
                                        if(source != 0)
-                                               light_sources[p + posnodes] = true;
+                                               light_sources.insert(p + posnodes);
 
                                        // Collect borders for unlighting
                                        if((x==0 || x == MAP_BLOCKSIZE-1
@@ -744,7 +743,7 @@ void Map::updateLighting(enum LightBank bank,
                                        && oldlight != 0)
                                        {
                                                v3s16 p_map = p + posnodes;
-                                               unlight_from.insert(p_map, oldlight);
+                                               unlight_from[p_map] = oldlight;
                                        }
                                }
                                catch(InvalidPositionException &e)
@@ -912,8 +911,8 @@ void Map::updateLighting(enum LightBank bank,
        //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
 }
 
-void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+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);
@@ -921,11 +920,11 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
        /*
                Update information about whether day and night light differ
        */
-       for(core::map<v3s16, MapBlock*>::Iterator
-                       i = modified_blocks.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator
+                       i = modified_blocks.begin();
+                       i != modified_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
+               MapBlock *block = i->second;
                block->expireDayNightDiff();
        }
 }
@@ -933,7 +932,8 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
 /*
 */
 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
-               core::map<v3s16, MapBlock*> &modified_blocks)
+               std::map<v3s16, MapBlock*> &modified_blocks,
+               bool remove_metadata)
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
@@ -949,10 +949,10 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        */
 
        v3s16 toppos = p + v3s16(0,1,0);
-       v3s16 bottompos = p + v3s16(0,-1,0);
+       //v3s16 bottompos = p + v3s16(0,-1,0);
 
        bool node_under_sunlight = true;
-       core::map<v3s16, bool> light_sources;
+       std::set<v3s16> light_sources;
 
        /*
                Collect old node for rollback
@@ -994,7 +994,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                v3s16 blockpos = getNodeBlockPos(p);
                MapBlock * block = getBlockNoCreate(blockpos);
                assert(block != NULL);
-               modified_blocks.insert(blockpos, block);
+               modified_blocks[blockpos] = block;
 
                assert(isValidPosition(p));
 
@@ -1020,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
@@ -1078,12 +1079,11 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        /*
                Update information about whether day and night light differ
        */
-       for(core::map<v3s16, MapBlock*>::Iterator
-                       i = modified_blocks.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator
+                       i = modified_blocks.begin();
+                       i != modified_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
-               block->expireDayNightDiff();
+               i->second->expireDayNightDiff();
        }
 
        /*
@@ -1132,7 +1132,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
 /*
 */
 void Map::removeNodeAndUpdate(v3s16 p,
-               core::map<v3s16, MapBlock*> &modified_blocks)
+               std::map<v3s16, MapBlock*> &modified_blocks)
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
@@ -1166,7 +1166,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
        {
        }
 
-       core::map<v3s16, bool> light_sources;
+       std::set<v3s16> light_sources;
 
        enum LightBank banks[] =
        {
@@ -1214,7 +1214,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
        v3s16 blockpos = getNodeBlockPos(p);
        MapBlock * block = getBlockNoCreate(blockpos);
        assert(block != NULL);
-       modified_blocks.insert(blockpos, block);
+       modified_blocks[blockpos] = block;
 
        /*
                If the removed node was under sunlight, propagate the
@@ -1259,7 +1259,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
                // Get the brightest neighbour node and propagate light from it
                v3s16 n2p = getBrightestNeighbour(bank, p);
                try{
-                       MapNode n2 = getNode(n2p);
+                       //MapNode n2 = getNode(n2p);
                        lightNeighbors(bank, n2p, modified_blocks);
                }
                catch(InvalidPositionException &e)
@@ -1270,12 +1270,11 @@ void Map::removeNodeAndUpdate(v3s16 p,
        /*
                Update information about whether day and night light differ
        */
-       for(core::map<v3s16, MapBlock*>::Iterator
-                       i = modified_blocks.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator
+                       i = modified_blocks.begin();
+                       i != modified_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
-               block->expireDayNightDiff();
+               i->second->expireDayNightDiff();
        }
 
        /*
@@ -1321,24 +1320,24 @@ 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{
-               core::map<v3s16, MapBlock*> modified_blocks;
-               addNodeAndUpdate(p, n, modified_blocks);
+               std::map<v3s16, MapBlock*> modified_blocks;
+               addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
 
                // Copy modified_blocks to event
-               for(core::map<v3s16, MapBlock*>::Iterator
-                               i = modified_blocks.getIterator();
-                               i.atEnd()==false; i++)
+               for(std::map<v3s16, MapBlock*>::iterator
+                               i = modified_blocks.begin();
+                               i != modified_blocks.end(); ++i)
                {
-                       event.modified_blocks.insert(i.getNode()->getKey(), false);
+                       event.modified_blocks.insert(i->first);
                }
        }
        catch(InvalidPositionException &e){
@@ -1358,15 +1357,15 @@ bool Map::removeNodeWithEvent(v3s16 p)
 
        bool succeeded = true;
        try{
-               core::map<v3s16, MapBlock*> modified_blocks;
+               std::map<v3s16, MapBlock*> modified_blocks;
                removeNodeAndUpdate(p, modified_blocks);
 
                // Copy modified_blocks to event
-               for(core::map<v3s16, MapBlock*>::Iterator
-                               i = modified_blocks.getIterator();
-                               i.atEnd()==false; i++)
+               for(std::map<v3s16, MapBlock*>::iterator
+                               i = modified_blocks.begin();
+                               i != modified_blocks.end(); ++i)
                {
-                       event.modified_blocks.insert(i.getNode()->getKey(), false);
+                       event.modified_blocks.insert(i->first);
                }
        }
        catch(InvalidPositionException &e){
@@ -1439,33 +1438,31 @@ bool Map::getDayNightDiff(v3s16 blockpos)
        Updates usage timers
 */
 void Map::timerUpdate(float dtime, float unload_timeout,
-               core::list<v3s16> *unloaded_blocks)
+               std::list<v3s16> *unloaded_blocks)
 {
        bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
 
        // Profile modified reasons
        Profiler modprofiler;
 
-       core::list<v2s16> sector_deletion_queue;
+       std::list<v2s16> sector_deletion_queue;
        u32 deleted_blocks_count = 0;
        u32 saved_blocks_count = 0;
        u32 block_count_all = 0;
 
-       core::map<v2s16, MapSector*>::Iterator si;
-
        beginSave();
-       si = m_sectors.getIterator();
-       for(; si.atEnd() == false; si++)
+       for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+               si != m_sectors.end(); ++si)
        {
-               MapSector *sector = si.getNode()->getValue();
+               MapSector *sector = si->second;
 
                bool all_blocks_deleted = true;
 
-               core::list<MapBlock*> blocks;
+               std::list<MapBlock*> blocks;
                sector->getBlocks(blocks);
 
-               for(core::list<MapBlock*>::Iterator i = blocks.begin();
-                               i != blocks.end(); i++)
+               for(std::list<MapBlock*>::iterator i = blocks.begin();
+                               i != blocks.end(); ++i)
                {
                        MapBlock *block = (*i);
 
@@ -1476,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++;
                                }
 
@@ -1501,7 +1498,7 @@ void Map::timerUpdate(float dtime, float unload_timeout,
 
                if(all_blocks_deleted)
                {
-                       sector_deletion_queue.push_back(si.getNode()->getKey());
+                       sector_deletion_queue.push_back(si->first);
                }
        }
        endSave();
@@ -1526,17 +1523,22 @@ void Map::timerUpdate(float dtime, float unload_timeout,
        }
 }
 
-void Map::deleteSectors(core::list<v2s16> &list)
+void Map::unloadUnreferencedBlocks(std::list<v3s16> *unloaded_blocks)
+{
+       timerUpdate(0.0, -1.0, unloaded_blocks);
+}
+
+void Map::deleteSectors(std::list<v2s16> &list)
 {
-       core::list<v2s16>::Iterator j;
-       for(j=list.begin(); j!=list.end(); j++)
+       for(std::list<v2s16>::iterator j = list.begin();
+               j != list.end(); ++j)
        {
                MapSector *sector = m_sectors[*j];
                // If sector is in sector cache, remove it from there
                if(m_sector_cache == sector)
                        m_sector_cache = NULL;
                // Remove from map and delete
-               m_sectors.remove(*j);
+               m_sectors.erase(*j);
                delete sector;
        }
 }
@@ -1615,7 +1617,6 @@ struct NodeNeighbor {
        NeighborType t;
        v3s16 p;
        bool l; //can liquid
-       bool i; //infinity
 };
 
 void Map::transforming_liquid_add(v3s16 p) {
@@ -1626,310 +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(core::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");
-
-       /*if(initial_size != 0)
-               infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
-
-       // 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)
-       core::map<v3s16, MapBlock*> lighting_modified_blocks;
-
-       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 >= 1000)
-                       break;
-               loopcount++;
-               /*
-                       Get a queued transforming liquid node
-               */
-               v3s16 p0 = m_transforming_liquid.pop_front();
-               u16 total_level = 0;
-               NodeNeighbor neighbors[7]; // surrounding flowing liquid nodes
-               s8 liquid_levels[7]      = {-1, -1, -1, -1, -1, -1, -1}; // current level of every block
-               s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1}; // target levels
-               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];
-               }
-
-               if (relax && p0.Y <= water_level && liquid_levels[D_TOP] == 0 && total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level - can_liquid_same_level + 2 && can_liquid_same_level >= relax + 1) { //relax up
-                       total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_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;
-
-               if (relax && p0.Y > water_level && liquid_levels[D_TOP] == 0 && liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 && total_level <= can_liquid_same_level - 2 && can_liquid_same_level >= relax + 1) { //relax down
-                       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
-                               && liquid_levels[ii] > liquid_levels_want[ii]
-                               ) {
-                               ++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 (liquid_levels_want[ii] >= 0 &&
-                               (neighbors[ii].i ||
-                                (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) //maybe == 1 // 
-                               for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
-                               if (!neighbors[ii].l)
-                                       continue;
-                               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.insert(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
-               if (changed)  for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
-                       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(core::map<v3s16, MapBlock*> & 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);
@@ -1945,12 +1644,14 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
        UniqueQueue<v3s16> must_reflow;
 
        // List of MapBlocks that will require a lighting update (due to lava)
-       core::map<v3s16, MapBlock*> lighting_modified_blocks;
+       std::map<v3s16, MapBlock*> lighting_modified_blocks;
+
+       u16 loop_max = g_settings->getU16("liquid_loop_max");
 
        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 >= 10000)
+               if(loopcount >= initial_size || loopcount >= loop_max)
                        break;
                loopcount++;
 
@@ -2060,6 +1761,7 @@ void Map::transformLiquids(core::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
@@ -2069,6 +1771,8 @@ void Map::transformLiquids(core::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++) {
@@ -2109,7 +1813,7 @@ void Map::transformLiquids(core::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;
@@ -2129,6 +1833,7 @@ void Map::transformLiquids(core::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
@@ -2165,9 +1870,10 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                v3s16 blockpos = getNodeBlockPos(p0);
                MapBlock *block = getBlockNoCreateNoEx(blockpos);
                if(block != NULL) {
-                       modified_blocks.insert(blockpos, block);
-                       // If node emits light, MapBlock requires lighting update
-                       if(nodemgr->get(n0).light_source != 0)
+                       modified_blocks[blockpos] =  block;
+                       // If new or old node emits light, MapBlock requires lighting update
+                       if(nodemgr->get(n0).light_source != 0 ||
+                                       nodemgr->get(n00).light_source != 0)
                                lighting_modified_blocks[block->getPos()] = block;
                }
 
@@ -2198,7 +1904,7 @@ void Map::transformLiquids(core::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;
@@ -2208,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;
@@ -2218,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;
@@ -2228,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)
@@ -2261,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();
@@ -2281,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;
@@ -2309,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;
 
@@ -2379,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;
@@ -2435,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
        /*
@@ -2455,24 +2153,30 @@ ServerMap::~ServerMap()
 #endif
 }
 
+u64 ServerMap::getSeed()
+{
+       return m_emerge->params.seed;
+}
+
+s16 ServerMap::getWaterLevel()
+{
+       return m_emerge->params.water_level;
+}
+
 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 = 3;
-       //v3s16 chunk_offset(-1,-1,-1);
-       //s16 chunksize = 4;
-       //v3s16 chunk_offset(-1,-1,-1);
-       s16 chunksize = 5;
-       v3s16 chunk_offset(-2,-2,-2);
+       s16 chunksize = m_emerge->params.chunksize;
+       s16 coffset = -chunksize / 2;
+       v3s16 chunk_offset(coffset, coffset, coffset);
        v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
        v3s16 blockpos_min = blockpos_div * chunksize;
        v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
        blockpos_min += chunk_offset;
        blockpos_max += chunk_offset;
 
-       //v3s16 extra_borders(1,1,1);
        v3s16 extra_borders(1,1,1);
 
        // Do nothing if not inside limits (+-1 because of neighbors)
@@ -2480,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;
@@ -2501,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++)
@@ -2548,9 +2253,9 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
        // Add the area
        {
                //TimeTaker timer("initBlockMake() initialEmerge");
-               data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
+               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++) {
@@ -2570,8 +2275,8 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
        return true;
 }
 
-MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
-               core::map<v3s16, MapBlock*> &changed_blocks)
+void ServerMap::finishBlockMake(BlockMakeData *data,
+               std::map<v3s16, MapBlock*> &changed_blocks)
 {
        v3s16 blockpos_min = data->blockpos_min;
        v3s16 blockpos_max = data->blockpos_max;
@@ -2607,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());
@@ -2664,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
@@ -2676,11 +2383,12 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
        /*
                Go through changed blocks
        */
-       for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
+                       i != changed_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
-               assert(block);
+               MapBlock *block = i->second;
+               if (!block)
+                       continue;
                /*
                        Update day/night difference cache of the MapBlocks
                */
@@ -2701,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);
        }
 
@@ -2714,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)
        {
@@ -2737,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)
@@ -2792,12 +2500,12 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
        sector = new ServerMapSector(this, p2d, m_gamedef);
 
        // Sector position on map in nodes
-       v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
+       //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
 
        /*
                Insert to container
        */
-       m_sectors.insert(p2d, sector);
+       m_sectors[p2d] = sector;
 
        return sector;
 }
@@ -2808,7 +2516,7 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
 */
 MapBlock * ServerMap::generateBlock(
                v3s16 p,
-               core::map<v3s16, MapBlock*> &modified_blocks
+               std::map<v3s16, MapBlock*> &modified_blocks
 )
 {
        DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
@@ -3006,9 +2714,11 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
 
                return block;
        }
-       /*if(allow_generate)
+
+#if 0
+       if(allow_generate)
        {
-               core::map<v3s16, MapBlock*> modified_blocks;
+               std::map<v3s16, MapBlock*> modified_blocks;
                MapBlock *block = generateBlock(p, modified_blocks);
                if(block)
                {
@@ -3017,11 +2727,11 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
                        event.p = p;
 
                        // Copy modified_blocks to event
-                       for(core::map<v3s16, MapBlock*>::Iterator
-                                       i = modified_blocks.getIterator();
-                                       i.atEnd()==false; i++)
+                       for(std::map<v3s16, MapBlock*>::iterator
+                                       i = modified_blocks.begin();
+                                       i != modified_blocks.end(); ++i)
                        {
-                               event.modified_blocks.insert(i.getNode()->getKey(), false);
+                               event.modified_blocks.insert(i->first);
                        }
 
                        // Queue event
@@ -3029,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
@@ -3078,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)
@@ -3182,24 +2836,26 @@ 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;
-       size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
-       assert(spos != std::string::npos);
-       if(dirname.size() - spos == 8)
+       std::string component;
+       fs::RemoveLastPathComponent(dirname, &component, 1);
+       if(component.size() == 8)
        {
                // Old layout
-               r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
+               r = sscanf(component.c_str(), "%4x%4x", &x, &y);
        }
-       else if(dirname.size() - spos == 3)
+       else if(component.size() == 3)
        {
                // New layout
-               r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
+               fs::RemoveLastPathComponent(dirname, &component, 2);
+               r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
                // Sign-extend the 12 bit values up to 16 bits...
                if(x&0x800) x|=0xF000;
                if(y&0x800) y|=0xF000;
@@ -3262,10 +2918,10 @@ void ServerMap::save(ModifiedState save_level)
        // Don't do anything with sqlite unless something is really saved
        bool save_started = false;
 
-       core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
-       for(; i.atEnd() == false; i++)
+       for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
+               i != m_sectors.end(); ++i)
        {
-               ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
+               ServerMapSector *sector = (ServerMapSector*)i->second;
                assert(sector->getId() == MAPSECTOR_SERVER);
 
                if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
@@ -3273,17 +2929,17 @@ void ServerMap::save(ModifiedState save_level)
                        saveSectorMeta(sector);
                        sector_meta_count++;
                }
-               core::list<MapBlock*> blocks;
+               std::list<MapBlock*> blocks;
                sector->getBlocks(blocks);
-               core::list<MapBlock*>::Iterator j;
 
-               for(j=blocks.begin(); j!=blocks.end(); j++)
+               for(std::list<MapBlock*>::iterator j = blocks.begin();
+                       j != blocks.end(); ++j)
                {
                        MapBlock *block = *j;
 
                        block_count_all++;
 
-                       if(block->getModified() >= save_level)
+                       if(block->getModified() >= (u32)save_level)
                        {
                                // Lazy beginSave()
                                if(!save_started){
@@ -3324,47 +2980,30 @@ 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(core::list<v3s16> &dst)
+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;
        }
+       dbase->listAllLoadableBlocks(dst);
+}
 
+void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst)
+{
+       for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+               si != m_sectors.end(); ++si)
        {
-               verifyDatabase();
+               MapSector *sector = si->second;
 
-               while(sqlite3_step(m_database_list) == SQLITE_ROW)
+               std::list<MapBlock*> blocks;
+               sector->getBlocks(blocks);
+
+               for(std::list<MapBlock*>::iterator i = blocks.begin();
+                               i != blocks.end(); ++i)
                {
-                       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;
+                       MapBlock *block = (*i);
+                       v3s16 p = block->getPos();
                        dst.push_back(p);
                }
        }
@@ -3381,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;
 }
@@ -3430,38 +3070,29 @@ void ServerMap::loadMapMeta()
                params.parseConfigLine(line);
        }
 
-       MapgenParams *mgparams = m_emerge->getParamsFromSettings(&params);
-       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;
-               }
-       }
+       m_emerge->loadParamsFromSettings(&params);
 
-       verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
+       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;
 }
@@ -3487,7 +3118,7 @@ MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load
                                        <<" Continuing with a sector with no metadata."
                                        <<std::endl;*/
                        sector = new ServerMapSector(this, p2d, m_gamedef);
-                       m_sectors.insert(p2d, sector);
+                       m_sectors[p2d] = sector;
                }
                else
                {
@@ -3622,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)
@@ -3757,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);
 
@@ -3776,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.
@@ -3824,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);
@@ -3858,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);
-
-                       loadBlock(&datastr, blockpos, sector, false);
+       std::string ret;
 
-                       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/
@@ -3952,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);
-               core::map<v3s16, u8>::Node *n;
-               n = m_loaded_blocks.find(p);
-               if(n != NULL)
-                       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.insert(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
-               (core::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)
 {
 }
 
@@ -4120,14 +3532,8 @@ 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)
+void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min,
+                                               v3s16 blockpos_max, bool load_if_inexistent)
 {
        TimeTaker timer1("initialEmerge", &emerge_time);
 
@@ -4156,9 +3562,9 @@ void ManualMapVoxelManipulator::initialEmerge(
                u8 flags = 0;
                MapBlock *block;
                v3s16 p(x,y,z);
-               core::map<v3s16, u8>::Node *n;
+               std::map<v3s16, u8>::iterator n;
                n = m_loaded_blocks.find(p);
-               if(n != NULL)
+               if(n != m_loaded_blocks.end())
                        continue;
 
                bool block_data_inexistent = false;
@@ -4179,18 +3585,28 @@ void ManualMapVoxelManipulator::initialEmerge(
 
                if(block_data_inexistent)
                {
-                       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
-                       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);
+
+                       if (load_if_inexistent) {
+                               ServerMap *svrmap = (ServerMap *)m_map;
+                               block = svrmap->emergeBlock(p, false);
+                               if (block == NULL)
+                                       block = svrmap->createBlock(p);
+                               else
+                                       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_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_NO_DATA, MAP_BLOCKSIZE);
+                               }
                        }
                }
                /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
@@ -4199,12 +3615,13 @@ void ManualMapVoxelManipulator::initialEmerge(
                        flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
                }*/
 
-               m_loaded_blocks.insert(p, flags);
+               m_loaded_blocks[p] = flags;
        }
 }
 
 void ManualMapVoxelManipulator::blitBackAll(
-               core::map<v3s16, MapBlock*> * modified_blocks)
+               std::map<v3s16, MapBlock*> *modified_blocks,
+               bool overwrite_generated)
 {
        if(m_area.getExtent() == v3s16(0,0,0))
                return;
@@ -4212,37 +3629,21 @@ void ManualMapVoxelManipulator::blitBackAll(
        /*
                Copy data of all blocks
        */
-       for(core::map<v3s16, u8>::Iterator
-                       i = m_loaded_blocks.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::map<v3s16, u8>::iterator
+                       i = m_loaded_blocks.begin();
+                       i != m_loaded_blocks.end(); ++i)
        {
-               v3s16 p = i.getNode()->getKey();
-               u8 flags = i.getNode()->getValue();
-               
-               bool existed = !(flags & VMANIP_BLOCK_DATA_INEXIST);
-               if(existed == false)
-               {
-                       // The Great Bug was found using this
-                       /*infostream<<"ManualMapVoxelManipulator::blitBackAll: "
-                                       <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
-                                       <<std::endl;*/
-                       continue;
-               }
-               
+               v3s16 p = i->first;
                MapBlock *block = m_map->getBlockNoCreateNoEx(p);
-               if(block == NULL)
-               {
-                       infostream<<"WARNING: "<<__FUNCTION_NAME
-                                       <<": got NULL block "
-                                       <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
-                                       <<std::endl;
+               bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
+               if ((existed == false) || (block == NULL) ||
+                       (overwrite_generated == false && block->isGenerated() == true))
                        continue;
-               }
 
                block->copyFrom(*this);
-               
+
                if(modified_blocks)
-                       modified_blocks->insert(p, block);
+                       (*modified_blocks)[p] = block;
        }
 }