]> git.lizzy.rs Git - minetest.git/blobdiff - src/map.cpp
Don't save alpha channel in screenshots (fixes #1451)
[minetest.git] / src / map.cpp
index 2845f3a67de7ed93228982da25769242ee9f5f2e..236972ae98a08751889f437e567e60709a2466f6 100644 (file)
@@ -1,6 +1,6 @@
 /*
 /*
-Minetest-c55
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+Minetest
+Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
@@ -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 "filesys.h"
 #include "voxel.h"
 #include "porting.h"
-#include "mapgen.h"
+#include "serialization.h"
 #include "nodemetadata.h"
 #include "settings.h"
 #include "log.h"
 #include "nodemetadata.h"
 #include "settings.h"
 #include "log.h"
@@ -32,20 +32,36 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "nodedef.h"
 #include "gamedef.h"
 #include "util/directiontables.h"
 #include "nodedef.h"
 #include "gamedef.h"
 #include "util/directiontables.h"
+#include "util/mathconstants.h"
 #include "rollback_interface.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<<")"
 
 /*
        SQLite format specification:
        - Initially only replaces sectors/ and sectors2/
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
 /*
        SQLite format specification:
        - Initially only replaces sectors/ and sectors2/
-       
+
        If map.sqlite does not exist in the save dir
        or the block was not found in the database
        the map will try to load from sectors folder.
        In either case, map.sqlite will be created
        and all future saves will save there.
        If map.sqlite does not exist in the save dir
        or the block was not found in the database
        the map will try to load from sectors folder.
        In either case, map.sqlite will be created
        and all future saves will save there.
-       
+
        Structure of map.sqlite:
        Tables:
                blocks
        Structure of map.sqlite:
        Tables:
                blocks
@@ -62,8 +78,6 @@ Map::Map(std::ostream &dout, IGameDef *gamedef):
        m_gamedef(gamedef),
        m_sector_cache(NULL)
 {
        m_gamedef(gamedef),
        m_sector_cache(NULL)
 {
-       /*m_sector_mutex.Init();
-       assert(m_sector_mutex.IsInitialized());*/
 }
 
 Map::~Map()
 }
 
 Map::~Map()
@@ -71,34 +85,30 @@ Map::~Map()
        /*
                Free all MapSectors
        */
        /*
                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)
 {
        }
 }
 
 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)
 {
 }
 
 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)
 {
 }
 
 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);
        }
 }
 
        }
 }
 
@@ -108,14 +118,14 @@ MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
                MapSector * sector = m_sector_cache;
                return sector;
        }
                MapSector * sector = m_sector_cache;
                return sector;
        }
-       
-       core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
-       
-       if(n == NULL)
+
+       std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
+
+       if(n == m_sectors.end())
                return NULL;
                return NULL;
-       
-       MapSector *sector = n->getValue();
-       
+
+       MapSector *sector = n->second;
+
        // Cache the last result
        m_sector_cache_p = p;
        m_sector_cache = sector;
        // Cache the last result
        m_sector_cache_p = p;
        m_sector_cache = sector;
@@ -133,7 +143,7 @@ MapSector * Map::getSectorNoGenerate(v2s16 p)
        MapSector *sector = getSectorNoGenerateNoEx(p);
        if(sector == NULL)
                throw InvalidPositionException();
        MapSector *sector = getSectorNoGenerateNoEx(p);
        if(sector == NULL)
                throw InvalidPositionException();
-       
+
        return sector;
 }
 
        return sector;
 }
 
@@ -148,7 +158,7 @@ MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
 }
 
 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
 }
 
 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
-{      
+{
        MapBlock *block = getBlockNoCreateNoEx(p3d);
        if(block == NULL)
                throw InvalidPositionException();
        MapBlock *block = getBlockNoCreateNoEx(p3d);
        if(block == NULL)
                throw InvalidPositionException();
@@ -234,9 +244,9 @@ void Map::setNode(v3s16 p, MapNode & n)
        values of from_nodes are lighting values.
 */
 void Map::unspreadLight(enum LightBank bank,
        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();
 
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -248,15 +258,13 @@ void Map::unspreadLight(enum LightBank bank,
                v3s16(0,-1,0), // bottom
                v3s16(-1,0,0), // left
        };
                v3s16(0,-1,0), // bottom
                v3s16(-1,0,0), // left
        };
-       
+
        if(from_nodes.size() == 0)
                return;
        if(from_nodes.size() == 0)
                return;
-       
+
        u32 blockchangecount = 0;
 
        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
 
        /*
                Initialize block cache
@@ -265,12 +273,13 @@ void Map::unspreadLight(enum LightBank bank,
        MapBlock *block = NULL;
        // Cache this a bit, too
        bool block_checked_in_modified = false;
        MapBlock *block = NULL;
        // 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);
                v3s16 blockpos = getNodeBlockPos(pos);
-               
+
                // Only fetch a new block if the block position has changed
                try{
                        if(block == NULL || blockpos != blockpos_last){
                // Only fetch a new block if the block position has changed
                try{
                        if(block == NULL || blockpos != blockpos_last){
@@ -290,12 +299,12 @@ void Map::unspreadLight(enum LightBank bank,
                        continue;
 
                // Calculate relative position in block
                        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
 
                // 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++)
 
                // Loop through 6 neighbors
                for(u16 i=0; i<6; i++)
@@ -352,7 +361,7 @@ void Map::unspreadLight(enum LightBank bank,
                                                n2.setLight(bank, 0, nodemgr);
                                                block->setNode(relpos, n2);
 
                                                n2.setLight(bank, 0, nodemgr);
                                                block->setNode(relpos, n2);
 
-                                               unlighted_nodes.insert(n2pos, current_light);
+                                               unlighted_nodes[n2pos] = current_light;
                                                changed = true;
 
                                                /*
                                                changed = true;
 
                                                /*
@@ -371,16 +380,16 @@ void Map::unspreadLight(enum LightBank bank,
                                                light_sources.remove(n2pos);*/
                                }
                                else{
                                                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.
                                }
 
                                // 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;
                                }
                                        }
                                        block_checked_in_modified = true;
                                }
@@ -406,11 +415,11 @@ void Map::unspreadLight(enum LightBank bank,
 */
 void Map::unLightNeighbors(enum LightBank bank,
                v3s16 pos, u8 lightwas,
 */
 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);
 }
 
        unspreadLight(bank, from_nodes, light_sources, modified_blocks);
 }
@@ -420,8 +429,8 @@ void Map::unLightNeighbors(enum LightBank bank,
        goes on recursively.
 */
 void Map::spreadLight(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();
 
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -439,9 +448,7 @@ void Map::spreadLight(enum LightBank bank,
 
        u32 blockchangecount = 0;
 
 
        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
 
        /*
                Initialize block cache
@@ -451,12 +458,10 @@ void Map::spreadLight(enum LightBank bank,
        // Cache this a bit, too
        bool block_checked_in_modified = false;
 
        // 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
                v3s16 blockpos = getNodeBlockPos(pos);
 
                // Only fetch a new block if the block position has changed
@@ -523,8 +528,7 @@ void Map::spreadLight(enum LightBank bank,
                                */
                                if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
                                {
                                */
                                if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
                                {
-                                       lighted_nodes.insert(n2pos, true);
-                                       //lighted_nodes.push_back(n2pos);
+                                       lighted_nodes.insert(n2pos);
                                        changed = true;
                                }
                                /*
                                        changed = true;
                                }
                                /*
@@ -537,8 +541,7 @@ void Map::spreadLight(enum LightBank bank,
                                        {
                                                n2.setLight(bank, newlight, nodemgr);
                                                block->setNode(relpos, n2);
                                        {
                                                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;
                                        }
                                }
                                                changed = true;
                                        }
                                }
@@ -547,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(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;
                                }
                                        }
                                        block_checked_in_modified = true;
                                }
@@ -575,10 +578,10 @@ void Map::spreadLight(enum LightBank bank,
 */
 void Map::lightNeighbors(enum LightBank bank,
                v3s16 pos,
 */
 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);
 }
 
        spreadLight(bank, from_nodes, modified_blocks);
 }
 
@@ -633,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,
        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();
 
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -660,7 +663,7 @@ s16 Map::propagateSunlight(v3s16 start,
                        n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
                        block->setNode(relpos, n);
 
                        n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
                        block->setNode(relpos, n);
 
-                       modified_blocks.insert(blockpos, block);
+                       modified_blocks[blockpos] = block;
                }
                else
                {
                }
                else
                {
@@ -672,8 +675,8 @@ s16 Map::propagateSunlight(v3s16 start,
 }
 
 void Map::updateLighting(enum LightBank bank,
 }
 
 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();
 
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -686,22 +689,21 @@ void Map::updateLighting(enum LightBank bank,
        //bool debug=true;
        //u32 count_was = modified_blocks.size();
 
        //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;
 
        int num_bottom_invalid = 0;
-       
+
        {
        //TimeTaker t("first stuff");
 
        {
        //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(;;)
                {
 
                for(;;)
                {
@@ -711,9 +713,8 @@ void Map::updateLighting(enum LightBank bank,
 
                        v3s16 pos = block->getPos();
                        v3s16 posnodes = block->getPosRelative();
 
                        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
 
                        /*
                                Clear all light from block
@@ -733,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)
                                        // 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
 
                                        // Collect borders for unlighting
                                        if((x==0 || x == MAP_BLOCKSIZE-1
@@ -742,7 +743,7 @@ void Map::updateLighting(enum LightBank bank,
                                        && oldlight != 0)
                                        {
                                                v3s16 p_map = p + posnodes;
                                        && oldlight != 0)
                                        {
                                                v3s16 p_map = p + posnodes;
-                                               unlight_from.insert(p_map, oldlight);
+                                               unlight_from[p_map] = oldlight;
                                        }
                                }
                                catch(InvalidPositionException &e)
                                        }
                                }
                                catch(InvalidPositionException &e)
@@ -847,7 +848,7 @@ void Map::updateLighting(enum LightBank bank,
 #if 0
        {
                //MapVoxelManipulator vmanip(this);
 #if 0
        {
                //MapVoxelManipulator vmanip(this);
-               
+
                // Make a manual voxel manipulator and load all the blocks
                // that touch the requested blocks
                ManualMapVoxelManipulator vmanip(this);
                // Make a manual voxel manipulator and load all the blocks
                // that touch the requested blocks
                ManualMapVoxelManipulator vmanip(this);
@@ -910,8 +911,8 @@ void Map::updateLighting(enum LightBank bank,
        //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
 }
 
        //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);
 {
        updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
        updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
@@ -919,11 +920,11 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
        /*
                Update information about whether day and night light differ
        */
        /*
                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();
        }
 }
                block->expireDayNightDiff();
        }
 }
@@ -931,14 +932,15 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
 /*
 */
 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
 /*
 */
 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();
 
        /*PrintInfo(m_dout);
        m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
                        <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
        /*PrintInfo(m_dout);
        m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
                        <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
-       
+
        /*
                From this node to nodes underneath:
                If lighting is sunlight (1.0), unlight neighbours and
        /*
                From this node to nodes underneath:
                If lighting is sunlight (1.0), unlight neighbours and
@@ -947,11 +949,11 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        */
 
        v3s16 toppos = p + v3s16(0,1,0);
        */
 
        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;
 
        bool node_under_sunlight = true;
-       core::map<v3s16, bool> light_sources;
-       
+       std::set<v3s16> light_sources;
+
        /*
                Collect old node for rollback
        */
        /*
                Collect old node for rollback
        */
@@ -992,7 +994,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                v3s16 blockpos = getNodeBlockPos(p);
                MapBlock * block = getBlockNoCreate(blockpos);
                assert(block != NULL);
                v3s16 blockpos = getNodeBlockPos(p);
                MapBlock * block = getBlockNoCreate(blockpos);
                assert(block != NULL);
-               modified_blocks.insert(blockpos, block);
+               modified_blocks[blockpos] = block;
 
                assert(isValidPosition(p));
 
 
                assert(isValidPosition(p));
 
@@ -1018,8 +1020,9 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        /*
                Remove node metadata
        */
        /*
                Remove node metadata
        */
-
-       removeNodeMetadata(p);
+       if (remove_metadata) {
+               removeNodeMetadata(p);
+       }
 
        /*
                Set the node on the map
 
        /*
                Set the node on the map
@@ -1076,12 +1079,11 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        /*
                Update information about whether day and night light differ
        */
        /*
                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();
        }
 
        /*
        }
 
        /*
@@ -1130,7 +1132,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
 /*
 */
 void Map::removeNodeAndUpdate(v3s16 p,
 /*
 */
 void Map::removeNodeAndUpdate(v3s16 p,
-               core::map<v3s16, MapBlock*> &modified_blocks)
+               std::map<v3s16, MapBlock*> &modified_blocks)
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
@@ -1164,7 +1166,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
        {
        }
 
        {
        }
 
-       core::map<v3s16, bool> light_sources;
+       std::set<v3s16> light_sources;
 
        enum LightBank banks[] =
        {
 
        enum LightBank banks[] =
        {
@@ -1212,7 +1214,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
        v3s16 blockpos = getNodeBlockPos(p);
        MapBlock * block = getBlockNoCreate(blockpos);
        assert(block != NULL);
        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
 
        /*
                If the removed node was under sunlight, propagate the
@@ -1257,7 +1259,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
                // Get the brightest neighbour node and propagate light from it
                v3s16 n2p = getBrightestNeighbour(bank, p);
                try{
                // 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)
                        lightNeighbors(bank, n2p, modified_blocks);
                }
                catch(InvalidPositionException &e)
@@ -1268,12 +1270,11 @@ void Map::removeNodeAndUpdate(v3s16 p,
        /*
                Update information about whether day and night light differ
        */
        /*
                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();
        }
 
        /*
        }
 
        /*
@@ -1319,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;
 {
        MapEditEvent event;
-       event.type = MEET_ADDNODE;
+       event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
        event.p = p;
        event.n = n;
 
        bool succeeded = true;
        try{
        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
 
                // 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){
                }
        }
        catch(InvalidPositionException &e){
@@ -1356,15 +1357,15 @@ bool Map::removeNodeWithEvent(v3s16 p)
 
        bool succeeded = true;
        try{
 
        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
                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){
                }
        }
        catch(InvalidPositionException &e){
@@ -1437,36 +1438,34 @@ bool Map::getDayNightDiff(v3s16 blockpos)
        Updates usage timers
 */
 void Map::timerUpdate(float dtime, float unload_timeout,
        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);
 {
        bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
-       
+
        // Profile modified reasons
        Profiler modprofiler;
        // 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;
 
        u32 deleted_blocks_count = 0;
        u32 saved_blocks_count = 0;
        u32 block_count_all = 0;
 
-       core::map<v2s16, MapSector*>::Iterator si;
-
        beginSave();
        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;
 
 
                bool all_blocks_deleted = true;
 
-               core::list<MapBlock*> blocks;
+               std::list<MapBlock*> blocks;
                sector->getBlocks(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);
                {
                        MapBlock *block = (*i);
-                       
+
                        block->incrementUsageTimer(dtime);
 
                        if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout)
                        block->incrementUsageTimer(dtime);
 
                        if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout)
@@ -1474,11 +1473,11 @@ void Map::timerUpdate(float dtime, float unload_timeout,
                                v3s16 p = block->getPos();
 
                                // Save if modified
                                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);
                                {
                                        modprofiler.add(block->getModifiedReason(), 1);
-                                       saveBlock(block);
+                                       if (!saveBlock(block))
+                                               continue;
                                        saved_blocks_count++;
                                }
 
                                        saved_blocks_count++;
                                }
 
@@ -1499,14 +1498,14 @@ void Map::timerUpdate(float dtime, float unload_timeout,
 
                if(all_blocks_deleted)
                {
 
                if(all_blocks_deleted)
                {
-                       sector_deletion_queue.push_back(si.getNode()->getKey());
+                       sector_deletion_queue.push_back(si->first);
                }
        }
        endSave();
                }
        }
        endSave();
-       
+
        // Finally delete the empty sectors
        deleteSectors(sector_deletion_queue);
        // Finally delete the empty sectors
        deleteSectors(sector_deletion_queue);
-       
+
        if(deleted_blocks_count != 0)
        {
                PrintInfo(infostream); // ServerMap/ClientMap:
        if(deleted_blocks_count != 0)
        {
                PrintInfo(infostream); // ServerMap/ClientMap:
@@ -1524,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
        {
                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;
        }
 }
                delete sector;
        }
 }
@@ -1560,7 +1564,7 @@ void Map::unloadUnusedData(float timeout,
                                i != blocks.end(); i++)
                {
                        MapBlock *block = (*i);
                                i != blocks.end(); i++)
                {
                        MapBlock *block = (*i);
-                       
+
                        if(block->getUsageTimer() > timeout)
                        {
                                // Save if modified
                        if(block->getUsageTimer() > timeout)
                        {
                                // Save if modified
@@ -1612,9 +1616,18 @@ struct NodeNeighbor {
        MapNode n;
        NeighborType t;
        v3s16 p;
        MapNode n;
        NeighborType t;
        v3s16 p;
+       bool l; //can liquid
 };
 
 };
 
-void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
+void Map::transforming_liquid_add(v3s16 p) {
+        m_transforming_liquid.push_back(p);
+}
+
+s32 Map::transforming_liquid_size() {
+        return m_transforming_liquid.size();
+}
+
+void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -1629,14 +1642,16 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
 
        // list of nodes that due to viscosity have not reached their max level height
        UniqueQueue<v3s16> must_reflow;
 
        // list of nodes that due to viscosity have not reached their max level height
        UniqueQueue<v3s16> must_reflow;
-       
+
        // List of MapBlocks that will require a lighting update (due to lava)
        // 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
 
        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++;
 
                        break;
                loopcount++;
 
@@ -1651,7 +1666,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                        Collect information about current node
                 */
                s8 liquid_level = -1;
                        Collect information about current node
                 */
                s8 liquid_level = -1;
-               u8 liquid_kind = CONTENT_IGNORE;
+               content_t liquid_kind = CONTENT_IGNORE;
                LiquidType liquid_type = nodemgr->get(n0).liquid_type;
                switch (liquid_type) {
                        case LIQUID_SOURCE:
                LiquidType liquid_type = nodemgr->get(n0).liquid_type;
                switch (liquid_type) {
                        case LIQUID_SOURCE:
@@ -1714,7 +1729,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                                        }
                                        break;
                                case LIQUID_SOURCE:
                                        }
                                        break;
                                case LIQUID_SOURCE:
-                                       // if this node is not (yet) of a liquid type, choose the first liquid type we encounter 
+                                       // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
                                        if (liquid_kind == CONTENT_AIR)
                                                liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
                                        if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
                                        if (liquid_kind == CONTENT_AIR)
                                                liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
                                        if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
@@ -1746,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;
                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
                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
@@ -1755,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;
                        // 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++) {
                } else {
                        // no surrounding sources, so get the maximum level that can flow into this node
                        for (u16 i = 0; i < num_flows; i++) {
@@ -1795,7 +1813,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                        } else
                                new_node_level = max_node_level;
 
                        } 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;
                                new_node_content = liquid_kind;
                        else
                                new_node_content = CONTENT_AIR;
@@ -1815,6 +1833,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                /*
                        update the current node
                 */
                /*
                        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
                //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
@@ -1824,7 +1843,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                        n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
                }
                n0.setContent(new_node_content);
                        n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
                }
                n0.setContent(new_node_content);
-               
+
                // Find out whether there is a suspect for this action
                std::string suspect;
                if(m_gamedef->rollback()){
                // Find out whether there is a suspect for this action
                std::string suspect;
                if(m_gamedef->rollback()){
@@ -1851,9 +1870,10 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                v3s16 blockpos = getNodeBlockPos(p0);
                MapBlock *block = getBlockNoCreateNoEx(blockpos);
                if(block != NULL) {
                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;
                }
 
                                lighting_modified_blocks[block->getPos()] = block;
                }
 
@@ -1884,7 +1904,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
        updateLighting(lighting_modified_blocks, 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;
 {
        v3s16 blockpos = getNodeBlockPos(p);
        v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
@@ -1894,8 +1914,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
                                <<std::endl;
                return NULL;
                infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
                                <<std::endl;
                return NULL;
@@ -1904,7 +1923,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p)
        return meta;
 }
 
        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;
 {
        v3s16 blockpos = getNodeBlockPos(p);
        v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
@@ -1914,13 +1933,13 @@ void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
                                <<std::endl;
                infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
                                <<std::endl;
-               return;
+               return false;
        }
        block->m_node_metadata.set(p_rel, meta);
        }
        block->m_node_metadata.set(p_rel, meta);
+       return true;
 }
 
 void Map::removeNodeMetadata(v3s16 p)
 }
 
 void Map::removeNodeMetadata(v3s16 p)
@@ -1947,8 +1966,7 @@ NodeTimer Map::getNodeTimer(v3s16 p)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::getNodeTimer(): Block not found"
                                <<std::endl;
                return NodeTimer();
                infostream<<"WARNING: Map::getNodeTimer(): Block not found"
                                <<std::endl;
                return NodeTimer();
@@ -1967,8 +1985,7 @@ void Map::setNodeTimer(v3s16 p, NodeTimer t)
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
                                <<PP(blockpos)<<std::endl;
                block = emergeBlock(blockpos, false);
        }
-       if(!block)
-       {
+       if(!block){
                infostream<<"WARNING: Map::setNodeTimer(): Block not found"
                                <<std::endl;
                return;
                infostream<<"WARNING: Map::setNodeTimer(): Block not found"
                                <<std::endl;
                return;
@@ -1993,42 +2010,43 @@ void Map::removeNodeTimer(v3s16 p)
 /*
        ServerMap
 */
 /*
        ServerMap
 */
-
-ServerMap::ServerMap(std::string savedir, IGameDef *gamedef):
+ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
        Map(dout_server, gamedef),
        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;
 
 {
        verbosestream<<__FUNCTION_NAME<<std::endl;
 
-       //m_chunksize = 8; // Takes a few seconds
-
-       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));
-       }
-       else
-       {
-               m_seed = g_settings->getU64("fixed_map_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;
 
        m_savedir = savedir;
        m_map_saving_enabled = false;
 
@@ -2050,6 +2068,10 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef):
                                        // Load map metadata (seed, chunksize)
                                        loadMapMeta();
                                }
                                        // Load map metadata (seed, chunksize)
                                        loadMapMeta();
                                }
+                               catch(SettingNotFoundException &e){
+                                       infostream<<"ServerMap:  Some metadata not found."
+                                                         <<" Using default settings."<<std::endl;
+                               }
                                catch(FileNotGoodException &e){
                                        infostream<<"WARNING: Could not load map metadata"
                                                        //<<" Disabling chunk-based generator."
                                catch(FileNotGoodException &e){
                                        infostream<<"WARNING: Could not load map metadata"
                                                        //<<" Disabling chunk-based generator."
@@ -2060,7 +2082,7 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef):
                                infostream<<"ServerMap: Successfully loaded map "
                                                <<"metadata from "<<savedir
                                                <<", assuming valid save directory."
                                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;
                                                <<std::endl;
 
                                m_map_saving_enabled = true;
@@ -2116,12 +2138,7 @@ ServerMap::~ServerMap()
        /*
                Close database if it was opened
        */
        /*
                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
        /*
 
 #if 0
        /*
@@ -2136,40 +2153,38 @@ ServerMap::~ServerMap()
 #endif
 }
 
 #endif
 }
 
-void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
+u64 ServerMap::getSeed()
 {
 {
-       bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
-       if(enable_mapgen_debug_info)
-               infostream<<"initBlockMake(): "
-                               <<"("<<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z<<") - "
-                               <<"("<<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z<<")"
-                               <<std::endl;
-       
-       //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);
+       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 = 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 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)
        if(blockpos_over_limit(blockpos_min - extra_borders) ||
                blockpos_over_limit(blockpos_max + extra_borders))
        v3s16 extra_borders(1,1,1);
 
        // Do nothing if not inside limits (+-1 because of neighbors)
        if(blockpos_over_limit(blockpos_min - extra_borders) ||
                blockpos_over_limit(blockpos_max + extra_borders))
-       {
-               data->no_op = true;
-               return;
-       }
-       
-       data->no_op = false;
-       data->seed = m_seed;
+               return false;
+
+       data->seed = m_emerge->params.seed;
        data->blockpos_min = blockpos_min;
        data->blockpos_max = blockpos_max;
        data->blockpos_requested = blockpos;
        data->blockpos_min = blockpos_min;
        data->blockpos_max = blockpos_max;
        data->blockpos_requested = blockpos;
@@ -2180,7 +2195,7 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
        */
        {
                //TimeTaker timer("initBlockMake() create area");
        */
        {
                //TimeTaker timer("initBlockMake() create area");
-               
+
                for(s16 x=blockpos_min.X-extra_borders.X;
                                x<=blockpos_max.X+extra_borders.X; x++)
                for(s16 z=blockpos_min.Z-extra_borders.Z;
                for(s16 x=blockpos_min.X-extra_borders.X;
                                x<=blockpos_max.X+extra_borders.X; x++)
                for(s16 z=blockpos_min.Z-extra_borders.Z;
@@ -2190,6 +2205,7 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
                        // Sector metadata is loaded from disk if not already loaded.
                        ServerMapSector *sector = createSector(sectorpos);
                        assert(sector);
                        // 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++)
 
                        for(s16 y=blockpos_min.Y-extra_borders.Y;
                                        y<=blockpos_max.Y+extra_borders.Y; y++)
@@ -2208,7 +2224,7 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
 
                                                Refer to the map generator heuristics.
                                        */
 
                                                Refer to the map generator heuristics.
                                        */
-                                       bool ug = mapgen::block_is_underground(data->seed, p);
+                                       bool ug = m_emerge->isBlockUnderground(p);
                                        block->setIsUnderground(ug);
                                }
 
                                        block->setIsUnderground(ug);
                                }
 
@@ -2219,32 +2235,48 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
                        }
                }
        }
                        }
                }
        }
-       
+
        /*
                Now we have a big empty area.
 
                Make a ManualMapVoxelManipulator that contains this and the
                neighboring blocks
        */
        /*
                Now we have a big empty area.
 
                Make a ManualMapVoxelManipulator that contains this and the
                neighboring blocks
        */
-       
+
        // The area that contains this block and it's neighbors
        v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
        v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
        // The area that contains this block and it's neighbors
        v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
        v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
-       
+
        data->vmanip = new ManualMapVoxelManipulator(this);
        //data->vmanip->setMap(this);
 
        // Add the area
        {
                //TimeTaker timer("initBlockMake() initialEmerge");
        data->vmanip = new ManualMapVoxelManipulator(this);
        //data->vmanip->setMap(this);
 
        // 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++) {
+                       for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
+                               core::map<v3s16, u8>::Node *n;
+                               n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
+                               if (n == NULL)
+                                       continue;
+                               u8 flags = n->getValue();
+                               flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
+                               n->setValue(flags);
+                       }
+               }
+       }*/
+
        // Data is ready now.
        // Data is ready now.
+       return true;
 }
 
 }
 
-MapBlock* ServerMap::finishBlockMake(mapgen::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;
 {
        v3s16 blockpos_min = data->blockpos_min;
        v3s16 blockpos_max = data->blockpos_max;
@@ -2255,13 +2287,7 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
 
        v3s16 extra_borders(1,1,1);
 
 
        v3s16 extra_borders(1,1,1);
 
-       if(data->no_op)
-       {
-               //infostream<<"finishBlockMake(): no-op"<<std::endl;
-               return NULL;
-       }
-
-       bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
+       bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
 
        /*infostream<<"Resulting vmanip:"<<std::endl;
        data->vmanip.print(infostream);*/
 
        /*infostream<<"Resulting vmanip:"<<std::endl;
        data->vmanip.print(infostream);*/
@@ -2289,9 +2315,7 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
                data->vmanip->blitBackAll(&changed_blocks);
        }
 
                data->vmanip->blitBackAll(&changed_blocks);
        }
 
-       if(enable_mapgen_debug_info)
-               infostream<<"finishBlockMake: changed_blocks.size()="
-                               <<changed_blocks.size()<<std::endl;
+       EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
 
        /*
                Copy transforming liquid information
 
        /*
                Copy transforming liquid information
@@ -2314,7 +2338,7 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
                TimeTaker t("finishBlockMake lighting update");
 
                core::map<v3s16, MapBlock*> lighting_update_blocks;
                TimeTaker t("finishBlockMake lighting update");
 
                core::map<v3s16, MapBlock*> lighting_update_blocks;
-               
+
                // Center blocks
                for(s16 x=blockpos_min.X-extra_borders.X;
                                x<=blockpos_max.X+extra_borders.X; x++)
                // Center blocks
                for(s16 x=blockpos_min.X-extra_borders.X;
                                x<=blockpos_max.X+extra_borders.X; x++)
@@ -2331,7 +2355,7 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
 
                updateLighting(lighting_update_blocks, changed_blocks);
 #endif
 
                updateLighting(lighting_update_blocks, changed_blocks);
 #endif
-               
+
                /*
                        Set lighting to non-expired state in all of them.
                        This is cheating, but it is not fast enough if all of them
                /*
                        Set lighting to non-expired state in all of them.
                        This is cheating, but it is not fast enough if all of them
@@ -2345,7 +2369,9 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
                                y<=blockpos_max.Y+extra_borders.Y; y++)
                {
                        v3s16 p(x, y, z);
                                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
                }
 
 #if 0
@@ -2357,11 +2383,12 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
        /*
                Go through changed blocks
        */
        /*
                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
                */
                /*
                        Update day/night difference cache of the MapBlocks
                */
@@ -2382,10 +2409,11 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
        {
                v3s16 p(x, y, z);
                MapBlock *block = getBlockNoCreateNoEx(p);
        {
                v3s16 p(x, y, z);
                MapBlock *block = getBlockNoCreateNoEx(p);
-               assert(block);
+               if (!block)
+                       continue;
                block->setGenerated(true);
        }
                block->setGenerated(true);
        }
-       
+
        /*
                Save changed parts of map
                NOTE: Will be saved later.
        /*
                Save changed parts of map
                NOTE: Will be saved later.
@@ -2395,6 +2423,8 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
        /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
                        <<","<<blockpos_requested.Y<<","
                        <<blockpos_requested.Z<<")"<<std::endl;*/
        /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
                        <<","<<blockpos_requested.Y<<","
                        <<blockpos_requested.Z<<")"<<std::endl;*/
+
+
 #if 0
        if(enable_mapgen_debug_info)
        {
 #if 0
        if(enable_mapgen_debug_info)
        {
@@ -2418,10 +2448,7 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
        }
 #endif
 
        }
 #endif
 
-       MapBlock *block = getBlockNoCreateNoEx(blockpos_requested);
-       assert(block);
-
-       return block;
+       getBlockNoCreateNoEx(blockpos_requested);
 }
 
 ServerMapSector * ServerMap::createSector(v2s16 p2d)
 }
 
 ServerMapSector * ServerMap::createSector(v2s16 p2d)
@@ -2429,14 +2456,14 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
        DSTACKF("%s: p2d=(%d,%d)",
                        __FUNCTION_NAME,
                        p2d.X, p2d.Y);
        DSTACKF("%s: p2d=(%d,%d)",
                        __FUNCTION_NAME,
                        p2d.X, p2d.Y);
-       
+
        /*
                Check if it exists already in memory
        */
        ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
        if(sector != NULL)
                return sector;
        /*
                Check if it exists already in memory
        */
        ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
        if(sector != NULL)
                return sector;
-       
+
        /*
                Try to load it from disk (with blocks)
        */
        /*
                Try to load it from disk (with blocks)
        */
@@ -2469,43 +2496,44 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
        /*
                Generate blank sector
        */
        /*
                Generate blank sector
        */
-       
+
        sector = new ServerMapSector(this, p2d, m_gamedef);
        sector = new ServerMapSector(this, p2d, m_gamedef);
-       
+
        // Sector position on map in nodes
        // Sector position on map in nodes
-       v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
+       //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
 
        /*
                Insert to container
        */
 
        /*
                Insert to container
        */
-       m_sectors.insert(p2d, sector);
-       
+       m_sectors[p2d] = sector;
+
        return sector;
 }
 
        return sector;
 }
 
+#if 0
 /*
        This is a quick-hand function for calling makeBlock().
 */
 MapBlock * ServerMap::generateBlock(
                v3s16 p,
 /*
        This is a quick-hand function for calling makeBlock().
 */
 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);
 )
 {
        DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
-       
+
        /*infostream<<"generateBlock(): "
                        <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
                        <<std::endl;*/
        /*infostream<<"generateBlock(): "
                        <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
                        <<std::endl;*/
-       
+
        bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
 
        TimeTaker timer("generateBlock");
        bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
 
        TimeTaker timer("generateBlock");
-       
+
        //MapBlock *block = original_dummy;
        //MapBlock *block = original_dummy;
-                       
+
        v2s16 p2d(p.X, p.Z);
        v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
        v2s16 p2d(p.X, p.Z);
        v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
-       
+
        /*
                Do not generate over-limit
        */
        /*
                Do not generate over-limit
        */
@@ -2518,7 +2546,7 @@ MapBlock * ServerMap::generateBlock(
        /*
                Create block make data
        */
        /*
                Create block make data
        */
-       mapgen::BlockMakeData data;
+       BlockMakeData data;
        initBlockMake(&data, p);
 
        /*
        initBlockMake(&data, p);
 
        /*
@@ -2526,7 +2554,8 @@ MapBlock * ServerMap::generateBlock(
        */
        {
                TimeTaker t("mapgen::make_block()");
        */
        {
                TimeTaker t("mapgen::make_block()");
-               mapgen::make_block(&data);
+               mapgen->makeChunk(&data);
+               //mapgen::make_block(&data);
 
                if(enable_mapgen_debug_info == false)
                        t.stop(true); // Hide output
 
                if(enable_mapgen_debug_info == false)
                        t.stop(true); // Hide output
@@ -2595,12 +2624,13 @@ MapBlock * ServerMap::generateBlock(
 
        return block;
 }
 
        return block;
 }
+#endif
 
 MapBlock * ServerMap::createBlock(v3s16 p)
 {
        DSTACKF("%s: p=(%d,%d,%d)",
                        __FUNCTION_NAME, p.X, p.Y, p.Z);
 
 MapBlock * ServerMap::createBlock(v3s16 p)
 {
        DSTACKF("%s: p=(%d,%d,%d)",
                        __FUNCTION_NAME, p.X, p.Y, p.Z);
-       
+
        /*
                Do not create over-limit
        */
        /*
                Do not create over-limit
        */
@@ -2611,7 +2641,7 @@ MapBlock * ServerMap::createBlock(v3s16 p)
        || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
        || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
                throw InvalidPositionException("createBlock(): pos. over limit");
        || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
        || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
                throw InvalidPositionException("createBlock(): pos. over limit");
-       
+
        v2s16 p2d(p.X, p.Z);
        s16 block_y = p.Y;
        /*
        v2s16 p2d(p.X, p.Z);
        s16 block_y = p.Y;
        /*
@@ -2656,15 +2686,16 @@ MapBlock * ServerMap::createBlock(v3s16 p)
        }
        // Create blank
        block = sector->createBlankBlock(block_y);
        }
        // Create blank
        block = sector->createBlankBlock(block_y);
+
        return block;
 }
 
        return block;
 }
 
-MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
+MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
 {
 {
-       DSTACKF("%s: p=(%d,%d,%d), allow_generate=%d",
+       DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
                        __FUNCTION_NAME,
                        __FUNCTION_NAME,
-                       p.X, p.Y, p.Z, allow_generate);
-       
+                       p.X, p.Y, p.Z, create_blank);
+
        {
                MapBlock *block = getBlockNoCreateNoEx(p);
                if(block && block->isDummy() == false)
        {
                MapBlock *block = getBlockNoCreateNoEx(p);
                if(block && block->isDummy() == false)
@@ -2677,9 +2708,17 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
                        return block;
        }
 
                        return block;
        }
 
+       if (create_blank) {
+               ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
+               MapBlock *block = sector->createBlankBlock(p.Y);
+
+               return block;
+       }
+
+#if 0
        if(allow_generate)
        {
        if(allow_generate)
        {
-               core::map<v3s16, MapBlock*> modified_blocks;
+               std::map<v3s16, MapBlock*> modified_blocks;
                MapBlock *block = generateBlock(p, modified_blocks);
                if(block)
                {
                MapBlock *block = generateBlock(p, modified_blocks);
                if(block)
                {
@@ -2688,23 +2727,58 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
                        event.p = p;
 
                        // Copy modified_blocks to event
                        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
                        dispatchEvent(&event);
                        }
 
                        // Queue event
                        dispatchEvent(&event);
-                                                               
+
                        return block;
                }
        }
                        return block;
                }
        }
+#endif
 
        return NULL;
 }
 
 
        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) {
+}
+
+// N.B.  This requires no synchronization, since data will not be modified unless
+// the VoxelManipulator being updated belongs to the same thread.
+void ServerMap::updateVManip(v3s16 pos)
+{
+       Mapgen *mg = m_emerge->getCurrentMapgen();
+       if (!mg)
+               return;
+
+       ManualMapVoxelManipulator *vm = mg->vm;
+       if (!vm)
+               return;
+
+       if (!vm->m_area.contains(pos))
+               return;
+
+       s32 idx = vm->m_area.index(pos);
+       vm->m_data[idx] = getNodeNoEx(pos);
+       vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA;
+
+       vm->m_is_dirty = true;
+}
+
 s16 ServerMap::findGroundLevel(v2s16 p2d)
 {
 #if 0
 s16 ServerMap::findGroundLevel(v2s16 p2d)
 {
 #if 0
@@ -2741,89 +2815,20 @@ s16 ServerMap::findGroundLevel(v2s16 p2d)
        /*
                Determine from map generator noise functions
        */
        /*
                Determine from map generator noise functions
        */
-       
-       s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1);
+
+       s16 level = m_emerge->getGroundLevelAtPoint(p2d);
        return level;
 
        //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
        //return (s16)level;
 }
 
        return level;
 
        //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
        //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() {
 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;
 }
 
                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)
 void ServerMap::createDirs(std::string path)
 {
        if(fs::CreateAllDirs(path) == false)
@@ -2853,24 +2858,26 @@ std::string ServerMap::getSectorDir(v2s16 pos, int layout)
                        return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
                default:
                        assert(false);
                        return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
                default:
                        assert(false);
+                       return "";
        }
 }
 
 v2s16 ServerMap::getSectorPos(std::string dirname)
 {
        }
 }
 
 v2s16 ServerMap::getSectorPos(std::string dirname)
 {
-       unsigned int x, y;
+       unsigned int x = 0, y = 0;
        int r;
        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
        {
                // 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
        {
                // 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;
                // Sign-extend the 12 bit values up to 16 bits...
                if(x&0x800) x|=0xF000;
                if(y&0x800) y|=0xF000;
@@ -2913,11 +2920,11 @@ void ServerMap::save(ModifiedState save_level)
                infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
                return;
        }
                infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
                return;
        }
-       
+
        if(save_level == MOD_STATE_CLEAN)
                infostream<<"ServerMap: Saving whole map, this can take time."
                                <<std::endl;
        if(save_level == MOD_STATE_CLEAN)
                infostream<<"ServerMap: Saving whole map, this can take time."
                                <<std::endl;
-       
+
        if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
        {
                saveMapMeta();
        if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
        {
                saveMapMeta();
@@ -2925,36 +2932,36 @@ void ServerMap::save(ModifiedState save_level)
 
        // Profile modified reasons
        Profiler modprofiler;
 
        // Profile modified reasons
        Profiler modprofiler;
-       
+
        u32 sector_meta_count = 0;
        u32 block_count = 0;
        u32 block_count_all = 0; // Number of blocks in memory
        u32 sector_meta_count = 0;
        u32 block_count = 0;
        u32 block_count_all = 0; // Number of blocks in memory
-       
+
        // Don't do anything with sqlite unless something is really saved
        bool save_started = false;
 
        // 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);
                assert(sector->getId() == MAPSECTOR_SERVER);
-       
+
                if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
                {
                        saveSectorMeta(sector);
                        sector_meta_count++;
                }
                if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
                {
                        saveSectorMeta(sector);
                        sector_meta_count++;
                }
-               core::list<MapBlock*> blocks;
+               std::list<MapBlock*> blocks;
                sector->getBlocks(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;
                {
                        MapBlock *block = *j;
-                       
+
                        block_count_all++;
 
                        block_count_all++;
 
-                       if(block->getModified() >= save_level)
+                       if(block->getModified() >= (u32)save_level)
                        {
                                // Lazy beginSave()
                                if(!save_started){
                        {
                                // Lazy beginSave()
                                if(!save_started){
@@ -2995,47 +3002,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;
        }
 {
        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();
-               
-               while(sqlite3_step(m_database_list) == SQLITE_ROW)
+               MapSector *sector = si->second;
+
+               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);
                }
        }
                        dst.push_back(p);
                }
        }
@@ -3044,36 +3034,37 @@ void ServerMap::listAllLoadableBlocks(core::list<v3s16> &dst)
 void ServerMap::saveMapMeta()
 {
        DSTACK(__FUNCTION_NAME);
 void ServerMap::saveMapMeta()
 {
        DSTACK(__FUNCTION_NAME);
-       
+
        /*infostream<<"ServerMap::saveMapMeta(): "
                        <<"seed="<<m_seed
                        <<std::endl;*/
 
        createDirs(m_savedir);
        /*infostream<<"ServerMap::saveMapMeta(): "
                        <<"seed="<<m_seed
                        <<std::endl;*/
 
        createDirs(m_savedir);
-       
+
        std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
        std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
-       std::ofstream os(fullpath.c_str(), std::ios_base::binary);
-       if(os.good() == false)
+       std::ostringstream ss(std::ios_base::binary);
+
+       Settings params;
+
+       m_emerge->saveParamsToSettings(&params);
+       params.writeLines(ss);
+
+       ss<<"[end_of_params]\n";
+
+       if(!fs::safeWriteToFile(fullpath, ss.str()))
        {
                infostream<<"ERROR: ServerMap::saveMapMeta(): "
        {
                infostream<<"ERROR: ServerMap::saveMapMeta(): "
-                               <<"could not open"<<fullpath<<std::endl;
-               throw FileNotGoodException("Cannot open chunk metadata");
+                               <<"could not write "<<fullpath<<std::endl;
+               throw FileNotGoodException("Cannot save chunk metadata");
        }
        }
-       
-       Settings params;
-       params.setU64("seed", m_seed);
 
 
-       params.writeLines(os);
-
-       os<<"[end_of_params]\n";
-       
        m_map_metadata_changed = false;
 }
 
 void ServerMap::loadMapMeta()
 {
        DSTACK(__FUNCTION_NAME);
        m_map_metadata_changed = false;
 }
 
 void ServerMap::loadMapMeta()
 {
        DSTACK(__FUNCTION_NAME);
-       
+
        /*infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
                        <<std::endl;*/
 
        /*infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
                        <<std::endl;*/
 
@@ -3101,28 +3092,30 @@ void ServerMap::loadMapMeta()
                params.parseConfigLine(line);
        }
 
                params.parseConfigLine(line);
        }
 
-       m_seed = params.getU64("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
 }
 
 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);
        // Get destination
        v2s16 pos = sector->getPos();
        std::string dir = getSectorDir(pos);
        createDirs(dir);
-       
+
        std::string fullpath = dir + DIR_DELIM + "meta";
        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);
+
+       if(!fs::safeWriteToFile(fullpath, ss.str()))
+               throw FileNotGoodException("Cannot write sector metafile");
 
 
-       sector->serialize(o, version);
-       
        sector->differs_from_disk = false;
 }
 
        sector->differs_from_disk = false;
 }
 
@@ -3147,7 +3140,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);
                                        <<" 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
                {
                }
                else
                {
@@ -3161,7 +3154,7 @@ MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load
                if(save_after_load)
                        saveSectorMeta(sector);
        }
                if(save_after_load)
                        saveSectorMeta(sector);
        }
-       
+
        sector->differs_from_disk = false;
 
        return sector;
        sector->differs_from_disk = false;
 
        return sector;
@@ -3206,7 +3199,7 @@ bool ServerMap::loadSectorMeta(v2s16 p2d)
        {
                return false;
        }
        {
                return false;
        }
-       
+
        return true;
 }
 
        return true;
 }
 
@@ -3250,7 +3243,7 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
        {
                return false;
        }
        {
                return false;
        }
-       
+
        /*
                Load blocks
        */
        /*
                Load blocks
        */
@@ -3282,99 +3275,69 @@ bool ServerMap::loadSectorFull(v2s16 p2d)
 }
 #endif
 
 }
 #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();
        v3s16 p3d = block->getPos();
-       
-       
-#if 0
-       v2s16 p2d(p3d.X, p3d.Z);
-       std::string sectordir = getSectorDir(p2d);
 
 
-       createDirs(sectordir);
+       // Dummy blocks are not written
+       if (block->isDummy()) {
+               errorstream << "WARNING: saveBlock: Not writing dummy block "
+                       << PP(p3d) << std::endl;
+               return true;
+       }
+
+       // 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
        */
        /*
                [0] u8 serialization version
                [1] data
        */
-       
-       verifyDatabase();
-       
        std::ostringstream o(std::ios_base::binary);
        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);
        block->serialize(o, version, true);
-       
-       // Write block to database
-       
-       std::string tmp = o.str();
-       const char *bytes = tmp.c_str();
-       
-       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;
-       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;
-       int written = sqlite3_step(m_database_write);
-       if(written != SQLITE_DONE)
-               infostream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
-               <<sqlite3_errmsg(m_database)<<std::endl;
-       // Make ready for later reuse
-       sqlite3_reset(m_database_write);
-       
-       // We just wrote it to the disk so clear modified flag
-       block->resetModified();
-}
-
-void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
+
+       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)
 {
        DSTACK(__FUNCTION_NAME);
 
        std::string fullpath = sectordir+DIR_DELIM+blockfile;
 {
        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)
                        throw FileNotGoodException("Cannot open block file");
 
                std::ifstream is(fullpath.c_str(), std::ios_base::binary);
                if(is.good() == false)
                        throw FileNotGoodException("Cannot open block file");
-               
+
                v3s16 p3d = getBlockPos(sectordir, blockfile);
                v2s16 p2d(p3d.X, p3d.Z);
                v3s16 p3d = getBlockPos(sectordir, blockfile);
                v2s16 p2d(p3d.X, p3d.Z);
-               
+
                assert(sector->getPos() == p2d);
                assert(sector->getPos() == p2d);
-               
+
                u8 version = SER_FMT_VER_INVALID;
                is.read((char*)&version, 1);
 
                u8 version = SER_FMT_VER_INVALID;
                is.read((char*)&version, 1);
 
@@ -3397,26 +3360,26 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
                        block = sector->createBlankBlockNoInsert(p3d.Y);
                        created_new = true;
                }
                        block = sector->createBlankBlockNoInsert(p3d.Y);
                        created_new = true;
                }
-               
+
                // Read basic data
                block->deSerialize(is, version, true);
 
                // If it's a new block, insert it to the map
                if(created_new)
                        sector->insertBlock(block);
                // Read basic data
                block->deSerialize(is, version, true);
 
                // If it's a new block, insert it to the map
                if(created_new)
                        sector->insertBlock(block);
-               
+
                /*
                        Save blocks loaded in old format in new format
                */
 
                /*
                        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);
                {
                        saveBlock(block);
-                       
+
                        // Should be in database now, so delete the old file
                        fs::RecursiveDelete(fullpath);
                }
                        // Should be in database now, so delete the old file
                        fs::RecursiveDelete(fullpath);
                }
-               
+
                // We just loaded it from the disk, so it's up-to-date.
                block->resetModified();
 
                // We just loaded it from the disk, so it's up-to-date.
                block->resetModified();
 
@@ -3428,7 +3391,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
                                <<" (SerializationError). "
                                <<"what()="<<e.what()
                                <<std::endl;
                                <<" (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.
                assert(0);
 
                // TODO: Backup file; name is in fullpath.
@@ -3441,7 +3404,7 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
 
        try {
                std::istringstream is(*blob, std::ios_base::binary);
 
        try {
                std::istringstream is(*blob, std::ios_base::binary);
-               
+
                u8 version = SER_FMT_VER_INVALID;
                is.read((char*)&version, 1);
 
                u8 version = SER_FMT_VER_INVALID;
                is.read((char*)&version, 1);
 
@@ -3464,23 +3427,23 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
                        block = sector->createBlankBlockNoInsert(p3d.Y);
                        created_new = true;
                }
                        block = sector->createBlankBlockNoInsert(p3d.Y);
                        created_new = true;
                }
-               
+
                // Read basic data
                block->deSerialize(is, version, true);
                // Read basic data
                block->deSerialize(is, version, true);
-               
+
                // If it's a new block, insert it to the map
                if(created_new)
                        sector->insertBlock(block);
                // If it's a new block, insert it to the map
                if(created_new)
                        sector->insertBlock(block);
-               
+
                /*
                        Save blocks loaded in old format in new format
                */
 
                /*
                        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);
                // Only save if asked to; no need to update version
                if(save_after_load)
                        saveBlock(block);
-               
+
                // We just loaded it from, so it's up-to-date.
                block->resetModified();
 
                // We just loaded it from, so it's up-to-date.
                block->resetModified();
 
@@ -3490,7 +3453,7 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
                errorstream<<"Invalid block data in database"
                                <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
                                <<" (SerializationError): "<<e.what()<<std::endl;
                errorstream<<"Invalid block data in database"
                                <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
                                <<" (SerializationError): "<<e.what()<<std::endl;
-               
+
                // TODO: Block should be marked as invalid in memory so that it is
                // not touched but the game can run
 
                // TODO: Block should be marked as invalid in memory so that it is
                // not touched but the game can run
 
@@ -3510,38 +3473,14 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
 
        v2s16 p2d(blockpos.X, blockpos.Z);
 
 
        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);
-
-                       sqlite3_step(m_database_read);
-                       // We should never get more than 1 row, so ok to reset
-                       sqlite3_reset(m_database_read);
+       std::string ret;
 
 
-                       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/
 
        // The directory layout we're going to load from.
        //  1 - original sectors/xxxxzzzz/
@@ -3560,7 +3499,7 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
                loadlayout = 2;
                sectordir = getSectorDir(p2d, 2);
        }
                loadlayout = 2;
                sectordir = getSectorDir(p2d, 2);
        }
-       
+
        /*
                Make sure sector is loaded
        */
        /*
                Make sure sector is loaded
        */
@@ -3583,7 +3522,7 @@ MapBlock* ServerMap::loadBlock(v3s16 blockpos)
                        return NULL;
                }
        }
                        return NULL;
                }
        }
-       
+
        /*
                Make sure file exists
        */
        /*
                Make sure file exists
        */
@@ -3604,158 +3543,11 @@ void ServerMap::PrintInfo(std::ostream &out)
        out<<"ServerMap: ";
 }
 
        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++)
-       {
-               v3s16 p(x,y,z);
-               core::map<v3s16, bool>::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;*/
-                       
-                       MapBlock *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)
-               {
-                       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);
-                       }
-               }
-
-               m_loaded_blocks.insert(p, !block_data_inexistent);
-       }
-
-       //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):
 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
-               MapVoxelManipulator(map),
-               m_create_area(false)
+               VoxelManipulator(),
+               m_is_dirty(false),
+               m_create_area(false),
+               m_map(map)
 {
 }
 
 {
 }
 
@@ -3763,14 +3555,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);
 
 {
        TimeTaker timer1("initialEmerge", &emerge_time);
 
@@ -3780,7 +3566,7 @@ void ManualMapVoxelManipulator::initialEmerge(
 
        VoxelArea block_area_nodes
                        (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
 
        VoxelArea block_area_nodes
                        (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
-       
+
        u32 size_MB = block_area_nodes.getVolume()*4/1000000;
        if(size_MB >= 1)
        {
        u32 size_MB = block_area_nodes.getVolume()*4/1000000;
        if(size_MB >= 1)
        {
@@ -3796,18 +3582,20 @@ void ManualMapVoxelManipulator::initialEmerge(
        for(s32 y=p_min.Y; y<=p_max.Y; y++)
        for(s32 x=p_min.X; x<=p_max.X; x++)
        {
        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);
                v3s16 p(x,y,z);
-               core::map<v3s16, bool>::Node *n;
+               std::map<v3s16, u8>::iterator n;
                n = m_loaded_blocks.find(p);
                n = m_loaded_blocks.find(p);
-               if(n != NULL)
+               if(n != m_loaded_blocks.end())
                        continue;
                        continue;
-               
+
                bool block_data_inexistent = false;
                try
                {
                        TimeTaker timer1("emerge load", &emerge_load_time);
 
                bool block_data_inexistent = false;
                try
                {
                        TimeTaker timer1("emerge load", &emerge_load_time);
 
-                       MapBlock *block = m_map->getBlockNoCreate(p);
+                       block = m_map->getBlockNoCreate(p);
                        if(block->isDummy())
                                block_data_inexistent = true;
                        else
                        if(block->isDummy())
                                block_data_inexistent = true;
                        else
@@ -3820,60 +3608,67 @@ void ManualMapVoxelManipulator::initialEmerge(
 
                if(block_data_inexistent)
                {
 
                if(block_data_inexistent)
                {
-                       /*
-                               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)
+               {
+                       // Mark that block was loaded as blank
+                       flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
+               }*/
 
 
-               m_loaded_blocks.insert(p, !block_data_inexistent);
+               m_loaded_blocks[p] = flags;
        }
        }
+
+       m_is_dirty = false;
 }
 
 void ManualMapVoxelManipulator::blitBackAll(
 }
 
 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;
 {
        if(m_area.getExtent() == v3s16(0,0,0))
                return;
-       
+
        /*
                Copy data of all blocks
        */
        /*
                Copy data of all blocks
        */
-       for(core::map<v3s16, bool>::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();
-               bool existed = i.getNode()->getValue();
-               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);
                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;
                        continue;
-               }
 
                block->copyFrom(*this);
 
                if(modified_blocks)
 
                block->copyFrom(*this);
 
                if(modified_blocks)
-                       modified_blocks->insert(p, block);
+                       (*modified_blocks)[p] = block;
        }
 }
 
        }
 }