]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/map.cpp
Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenu
[dragonfireclient.git] / src / map.cpp
index ea82194b85ccca4211797f6de18d51d08d256674..62ba85c4774c085162a78755eb6ac9b73edae4c6 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
@@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "filesys.h"
 #include "voxel.h"
 #include "porting.h"
-#include "mapgen.h"
+#include "serialization.h"
 #include "nodemetadata.h"
 #include "settings.h"
 #include "log.h"
@@ -32,8 +32,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "nodedef.h"
 #include "gamedef.h"
 #include "util/directiontables.h"
+#include "util/mathconstants.h"
 #include "rollback_interface.h"
+#include "environment.h"
+#include "emerge.h"
 #include "mapgen_v6.h"
+#include "biome.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
 
@@ -72,34 +76,30 @@ Map::~Map()
        /*
                Free all MapSectors
        */
-       core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
-       for(; i.atEnd() == false; i++)
+       for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
+               i != m_sectors.end(); ++i)
        {
-               MapSector *sector = i.getNode()->getValue();
-               delete sector;
+               delete i->second;
        }
 }
 
 void Map::addEventReceiver(MapEventReceiver *event_receiver)
 {
-       m_event_receivers.insert(event_receiver, false);
+       m_event_receivers.insert(event_receiver);
 }
 
 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
 {
-       if(m_event_receivers.find(event_receiver) == NULL)
-               return;
-       m_event_receivers.remove(event_receiver);
+       m_event_receivers.erase(event_receiver);
 }
 
 void Map::dispatchEvent(MapEditEvent *event)
 {
-       for(core::map<MapEventReceiver*, bool>::Iterator
-                       i = m_event_receivers.getIterator();
-                       i.atEnd()==false; i++)
+       for(std::set<MapEventReceiver*>::iterator
+                       i = m_event_receivers.begin();
+                       i != m_event_receivers.end(); ++i)
        {
-               MapEventReceiver* event_receiver = i.getNode()->getKey();
-               event_receiver->onMapEditEvent(event);
+               (*i)->onMapEditEvent(event);
        }
 }
 
@@ -110,12 +110,12 @@ MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
                return sector;
        }
 
-       core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
+       std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
 
-       if(n == NULL)
+       if(n == m_sectors.end())
                return NULL;
 
-       MapSector *sector = n->getValue();
+       MapSector *sector = n->second;
 
        // Cache the last result
        m_sector_cache_p = p;
@@ -235,9 +235,9 @@ void Map::setNode(v3s16 p, MapNode & n)
        values of from_nodes are lighting values.
 */
 void Map::unspreadLight(enum LightBank bank,
-               core::map<v3s16, u8> & from_nodes,
-               core::map<v3s16, bool> & light_sources,
-               core::map<v3s16, MapBlock*>  & modified_blocks)
+               std::map<v3s16, u8> & from_nodes,
+               std::set<v3s16> & light_sources,
+               std::map<v3s16, MapBlock*>  & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -255,9 +255,7 @@ void Map::unspreadLight(enum LightBank bank,
 
        u32 blockchangecount = 0;
 
-       core::map<v3s16, u8> unlighted_nodes;
-       core::map<v3s16, u8>::Iterator j;
-       j = from_nodes.getIterator();
+       std::map<v3s16, u8> unlighted_nodes;
 
        /*
                Initialize block cache
@@ -267,9 +265,10 @@ void Map::unspreadLight(enum LightBank bank,
        // Cache this a bit, too
        bool block_checked_in_modified = false;
 
-       for(; j.atEnd() == false; j++)
+       for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
+               j != from_nodes.end(); ++j)
        {
-               v3s16 pos = j.getNode()->getKey();
+               v3s16 pos = j->first;
                v3s16 blockpos = getNodeBlockPos(pos);
 
                // Only fetch a new block if the block position has changed
@@ -291,12 +290,12 @@ void Map::unspreadLight(enum LightBank bank,
                        continue;
 
                // Calculate relative position in block
-               v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
+               //v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
 
                // Get node straight from the block
-               MapNode n = block->getNode(relpos);
+               //MapNode n = block->getNode(relpos);
 
-               u8 oldlight = j.getNode()->getValue();
+               u8 oldlight = j->second;
 
                // Loop through 6 neighbors
                for(u16 i=0; i<6; i++)
@@ -353,7 +352,7 @@ void Map::unspreadLight(enum LightBank bank,
                                                n2.setLight(bank, 0, nodemgr);
                                                block->setNode(relpos, n2);
 
-                                               unlighted_nodes.insert(n2pos, current_light);
+                                               unlighted_nodes[n2pos] = current_light;
                                                changed = true;
 
                                                /*
@@ -372,16 +371,16 @@ void Map::unspreadLight(enum LightBank bank,
                                                light_sources.remove(n2pos);*/
                                }
                                else{
-                                       light_sources.insert(n2pos, true);
+                                       light_sources.insert(n2pos);
                                }
 
                                // Add to modified_blocks
                                if(changed == true && block_checked_in_modified == false)
                                {
                                        // If the block is not found in modified_blocks, add.
-                                       if(modified_blocks.find(blockpos) == NULL)
+                                       if(modified_blocks.find(blockpos) == modified_blocks.end())
                                        {
-                                               modified_blocks.insert(blockpos, block);
+                                               modified_blocks[blockpos] = block;
                                        }
                                        block_checked_in_modified = true;
                                }
@@ -407,11 +406,11 @@ void Map::unspreadLight(enum LightBank bank,
 */
 void Map::unLightNeighbors(enum LightBank bank,
                v3s16 pos, u8 lightwas,
-               core::map<v3s16, bool> & light_sources,
-               core::map<v3s16, MapBlock*>  & modified_blocks)
+               std::set<v3s16> & light_sources,
+               std::map<v3s16, MapBlock*>  & modified_blocks)
 {
-       core::map<v3s16, u8> from_nodes;
-       from_nodes.insert(pos, lightwas);
+       std::map<v3s16, u8> from_nodes;
+       from_nodes[pos] = lightwas;
 
        unspreadLight(bank, from_nodes, light_sources, modified_blocks);
 }
@@ -421,8 +420,8 @@ void Map::unLightNeighbors(enum LightBank bank,
        goes on recursively.
 */
 void Map::spreadLight(enum LightBank bank,
-               core::map<v3s16, bool> & from_nodes,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+               std::set<v3s16> & from_nodes,
+               std::map<v3s16, MapBlock*> & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -440,9 +439,7 @@ void Map::spreadLight(enum LightBank bank,
 
        u32 blockchangecount = 0;
 
-       core::map<v3s16, bool> lighted_nodes;
-       core::map<v3s16, bool>::Iterator j;
-       j = from_nodes.getIterator();
+       std::set<v3s16> lighted_nodes;
 
        /*
                Initialize block cache
@@ -452,12 +449,10 @@ void Map::spreadLight(enum LightBank bank,
        // Cache this a bit, too
        bool block_checked_in_modified = false;
 
-       for(; j.atEnd() == false; j++)
-       //for(; j != from_nodes.end(); j++)
+       for(std::set<v3s16>::iterator j = from_nodes.begin();
+               j != from_nodes.end(); ++j)
        {
-               v3s16 pos = j.getNode()->getKey();
-               //v3s16 pos = *j;
-               //infostream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
+               v3s16 pos = *j;
                v3s16 blockpos = getNodeBlockPos(pos);
 
                // Only fetch a new block if the block position has changed
@@ -524,8 +519,7 @@ void Map::spreadLight(enum LightBank bank,
                                */
                                if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
                                {
-                                       lighted_nodes.insert(n2pos, true);
-                                       //lighted_nodes.push_back(n2pos);
+                                       lighted_nodes.insert(n2pos);
                                        changed = true;
                                }
                                /*
@@ -538,8 +532,7 @@ void Map::spreadLight(enum LightBank bank,
                                        {
                                                n2.setLight(bank, newlight, nodemgr);
                                                block->setNode(relpos, n2);
-                                               lighted_nodes.insert(n2pos, true);
-                                               //lighted_nodes.push_back(n2pos);
+                                               lighted_nodes.insert(n2pos);
                                                changed = true;
                                        }
                                }
@@ -548,9 +541,9 @@ void Map::spreadLight(enum LightBank bank,
                                if(changed == true && block_checked_in_modified == false)
                                {
                                        // If the block is not found in modified_blocks, add.
-                                       if(modified_blocks.find(blockpos) == NULL)
+                                       if(modified_blocks.find(blockpos) == modified_blocks.end())
                                        {
-                                               modified_blocks.insert(blockpos, block);
+                                               modified_blocks[blockpos] = block;
                                        }
                                        block_checked_in_modified = true;
                                }
@@ -576,10 +569,10 @@ void Map::spreadLight(enum LightBank bank,
 */
 void Map::lightNeighbors(enum LightBank bank,
                v3s16 pos,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+               std::map<v3s16, MapBlock*> & modified_blocks)
 {
-       core::map<v3s16, bool> from_nodes;
-       from_nodes.insert(pos, true);
+       std::set<v3s16> from_nodes;
+       from_nodes.insert(pos);
        spreadLight(bank, from_nodes, modified_blocks);
 }
 
@@ -634,7 +627,7 @@ v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
        Mud is turned into grass in where the sunlight stops.
 */
 s16 Map::propagateSunlight(v3s16 start,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+               std::map<v3s16, MapBlock*> & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -661,7 +654,7 @@ s16 Map::propagateSunlight(v3s16 start,
                        n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
                        block->setNode(relpos, n);
 
-                       modified_blocks.insert(blockpos, block);
+                       modified_blocks[blockpos] = block;
                }
                else
                {
@@ -673,8 +666,8 @@ s16 Map::propagateSunlight(v3s16 start,
 }
 
 void Map::updateLighting(enum LightBank bank,
-               core::map<v3s16, MapBlock*> & a_blocks,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+               std::map<v3s16, MapBlock*> & a_blocks,
+               std::map<v3s16, MapBlock*> & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -687,22 +680,21 @@ void Map::updateLighting(enum LightBank bank,
        //bool debug=true;
        //u32 count_was = modified_blocks.size();
 
-       core::map<v3s16, MapBlock*> blocks_to_update;
+       std::map<v3s16, MapBlock*> blocks_to_update;
 
-       core::map<v3s16, bool> light_sources;
+       std::set<v3s16> light_sources;
 
-       core::map<v3s16, u8> unlight_from;
+       std::map<v3s16, u8> unlight_from;
 
        int num_bottom_invalid = 0;
 
        {
        //TimeTaker t("first stuff");
 
-       core::map<v3s16, MapBlock*>::Iterator i;
-       i = a_blocks.getIterator();
-       for(; i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator i = a_blocks.begin();
+               i != a_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
+               MapBlock *block = i->second;
 
                for(;;)
                {
@@ -712,9 +704,8 @@ void Map::updateLighting(enum LightBank bank,
 
                        v3s16 pos = block->getPos();
                        v3s16 posnodes = block->getPosRelative();
-                       modified_blocks.insert(pos, block);
-
-                       blocks_to_update.insert(pos, block);
+                       modified_blocks[pos] = block;
+                       blocks_to_update[pos] = block;
 
                        /*
                                Clear all light from block
@@ -734,7 +725,7 @@ void Map::updateLighting(enum LightBank bank,
                                        // If node sources light, add to list
                                        u8 source = nodemgr->get(n).light_source;
                                        if(source != 0)
-                                               light_sources[p + posnodes] = true;
+                                               light_sources.insert(p + posnodes);
 
                                        // Collect borders for unlighting
                                        if((x==0 || x == MAP_BLOCKSIZE-1
@@ -743,7 +734,7 @@ void Map::updateLighting(enum LightBank bank,
                                        && oldlight != 0)
                                        {
                                                v3s16 p_map = p + posnodes;
-                                               unlight_from.insert(p_map, oldlight);
+                                               unlight_from[p_map] = oldlight;
                                        }
                                }
                                catch(InvalidPositionException &e)
@@ -911,8 +902,8 @@ void Map::updateLighting(enum LightBank bank,
        //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
 }
 
-void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
-               core::map<v3s16, MapBlock*> & modified_blocks)
+void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
+               std::map<v3s16, MapBlock*> & modified_blocks)
 {
        updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
        updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
@@ -920,11 +911,11 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
        /*
                Update information about whether day and night light differ
        */
-       for(core::map<v3s16, MapBlock*>::Iterator
-                       i = modified_blocks.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator
+                       i = modified_blocks.begin();
+                       i != modified_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
+               MapBlock *block = i->second;
                block->expireDayNightDiff();
        }
 }
@@ -932,7 +923,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
 /*
 */
 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
-               core::map<v3s16, MapBlock*> &modified_blocks)
+               std::map<v3s16, MapBlock*> &modified_blocks)
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
@@ -948,10 +939,10 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        */
 
        v3s16 toppos = p + v3s16(0,1,0);
-       v3s16 bottompos = p + v3s16(0,-1,0);
+       //v3s16 bottompos = p + v3s16(0,-1,0);
 
        bool node_under_sunlight = true;
-       core::map<v3s16, bool> light_sources;
+       std::set<v3s16> light_sources;
 
        /*
                Collect old node for rollback
@@ -993,7 +984,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                v3s16 blockpos = getNodeBlockPos(p);
                MapBlock * block = getBlockNoCreate(blockpos);
                assert(block != NULL);
-               modified_blocks.insert(blockpos, block);
+               modified_blocks[blockpos] = block;
 
                assert(isValidPosition(p));
 
@@ -1077,12 +1068,11 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        /*
                Update information about whether day and night light differ
        */
-       for(core::map<v3s16, MapBlock*>::Iterator
-                       i = modified_blocks.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator
+                       i = modified_blocks.begin();
+                       i != modified_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
-               block->expireDayNightDiff();
+               i->second->expireDayNightDiff();
        }
 
        /*
@@ -1099,6 +1089,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        /*
                Add neighboring liquid nodes and the node itself if it is
                liquid (=water node was added) to transform queue.
+               note: todo: for liquid_finite enough to add only self node
        */
        v3s16 dirs[7] = {
                v3s16(0,0,0), // self
@@ -1131,7 +1122,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
 /*
 */
 void Map::removeNodeAndUpdate(v3s16 p,
-               core::map<v3s16, MapBlock*> &modified_blocks)
+               std::map<v3s16, MapBlock*> &modified_blocks)
 {
        INodeDefManager *ndef = m_gamedef->ndef();
 
@@ -1165,7 +1156,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
        {
        }
 
-       core::map<v3s16, bool> light_sources;
+       std::set<v3s16> light_sources;
 
        enum LightBank banks[] =
        {
@@ -1213,7 +1204,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
        v3s16 blockpos = getNodeBlockPos(p);
        MapBlock * block = getBlockNoCreate(blockpos);
        assert(block != NULL);
-       modified_blocks.insert(blockpos, block);
+       modified_blocks[blockpos] = block;
 
        /*
                If the removed node was under sunlight, propagate the
@@ -1258,7 +1249,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
                // Get the brightest neighbour node and propagate light from it
                v3s16 n2p = getBrightestNeighbour(bank, p);
                try{
-                       MapNode n2 = getNode(n2p);
+                       //MapNode n2 = getNode(n2p);
                        lightNeighbors(bank, n2p, modified_blocks);
                }
                catch(InvalidPositionException &e)
@@ -1269,12 +1260,11 @@ void Map::removeNodeAndUpdate(v3s16 p,
        /*
                Update information about whether day and night light differ
        */
-       for(core::map<v3s16, MapBlock*>::Iterator
-                       i = modified_blocks.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator
+                       i = modified_blocks.begin();
+                       i != modified_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
-               block->expireDayNightDiff();
+               i->second->expireDayNightDiff();
        }
 
        /*
@@ -1291,6 +1281,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
        /*
                Add neighboring liquid nodes and this node to transform queue.
                (it's vital for the node itself to get updated last.)
+               note: todo: for liquid_finite enough to add only self node
        */
        v3s16 dirs[7] = {
                v3s16(0,0,1), // back
@@ -1329,15 +1320,15 @@ bool Map::addNodeWithEvent(v3s16 p, MapNode n)
 
        bool succeeded = true;
        try{
-               core::map<v3s16, MapBlock*> modified_blocks;
+               std::map<v3s16, MapBlock*> modified_blocks;
                addNodeAndUpdate(p, n, 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){
@@ -1357,15 +1348,15 @@ bool Map::removeNodeWithEvent(v3s16 p)
 
        bool succeeded = true;
        try{
-               core::map<v3s16, MapBlock*> modified_blocks;
+               std::map<v3s16, MapBlock*> modified_blocks;
                removeNodeAndUpdate(p, modified_blocks);
 
                // Copy modified_blocks to event
-               for(core::map<v3s16, MapBlock*>::Iterator
-                               i = modified_blocks.getIterator();
-                               i.atEnd()==false; i++)
+               for(std::map<v3s16, MapBlock*>::iterator
+                               i = modified_blocks.begin();
+                               i != modified_blocks.end(); ++i)
                {
-                       event.modified_blocks.insert(i.getNode()->getKey(), false);
+                       event.modified_blocks.insert(i->first);
                }
        }
        catch(InvalidPositionException &e){
@@ -1438,33 +1429,31 @@ bool Map::getDayNightDiff(v3s16 blockpos)
        Updates usage timers
 */
 void Map::timerUpdate(float dtime, float unload_timeout,
-               core::list<v3s16> *unloaded_blocks)
+               std::list<v3s16> *unloaded_blocks)
 {
        bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
 
        // Profile modified reasons
        Profiler modprofiler;
 
-       core::list<v2s16> sector_deletion_queue;
+       std::list<v2s16> sector_deletion_queue;
        u32 deleted_blocks_count = 0;
        u32 saved_blocks_count = 0;
        u32 block_count_all = 0;
 
-       core::map<v2s16, MapSector*>::Iterator si;
-
        beginSave();
-       si = m_sectors.getIterator();
-       for(; si.atEnd() == false; si++)
+       for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+               si != m_sectors.end(); ++si)
        {
-               MapSector *sector = si.getNode()->getValue();
+               MapSector *sector = si->second;
 
                bool all_blocks_deleted = true;
 
-               core::list<MapBlock*> blocks;
+               std::list<MapBlock*> blocks;
                sector->getBlocks(blocks);
 
-               for(core::list<MapBlock*>::Iterator i = blocks.begin();
-                               i != blocks.end(); i++)
+               for(std::list<MapBlock*>::iterator i = blocks.begin();
+                               i != blocks.end(); ++i)
                {
                        MapBlock *block = (*i);
 
@@ -1500,7 +1489,7 @@ void Map::timerUpdate(float dtime, float unload_timeout,
 
                if(all_blocks_deleted)
                {
-                       sector_deletion_queue.push_back(si.getNode()->getKey());
+                       sector_deletion_queue.push_back(si->first);
                }
        }
        endSave();
@@ -1525,17 +1514,22 @@ void Map::timerUpdate(float dtime, float unload_timeout,
        }
 }
 
-void Map::deleteSectors(core::list<v2s16> &list)
+void Map::unloadUnreferencedBlocks(std::list<v3s16> *unloaded_blocks)
 {
-       core::list<v2s16>::Iterator j;
-       for(j=list.begin(); j!=list.end(); j++)
+       timerUpdate(0.0, -1.0, unloaded_blocks);
+}
+
+void Map::deleteSectors(std::list<v2s16> &list)
+{
+       for(std::list<v2s16>::iterator j = list.begin();
+               j != list.end(); ++j)
        {
                MapSector *sector = m_sectors[*j];
                // If sector is in sector cache, remove it from there
                if(m_sector_cache == sector)
                        m_sector_cache = NULL;
                // Remove from map and delete
-               m_sectors.remove(*j);
+               m_sectors.erase(*j);
                delete sector;
        }
 }
@@ -1613,9 +1607,35 @@ struct NodeNeighbor {
        MapNode n;
        NeighborType t;
        v3s16 p;
+       bool l; //can liquid
+       bool i; //infinity
+};
+
+void Map::transforming_liquid_add(v3s16 p) {
+        m_transforming_liquid.push_back(p);
+}
+
+s32 Map::transforming_liquid_size() {
+        return m_transforming_liquid.size();
+}
+
+const v3s16 g_7dirs[7] =
+{
+       // +right, +top, +back
+       v3s16( 0,-1, 0), // bottom
+       v3s16( 0, 0, 0), // self
+       v3s16( 0, 0, 1), // back
+       v3s16( 0, 0,-1), // front
+       v3s16( 1, 0, 0), // right
+       v3s16(-1, 0, 0), // left
+       v3s16( 0, 1, 0)  // top
 };
 
-void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
+#define D_BOTTOM 0
+#define D_TOP 6
+#define D_SELF 1
+
+void Map::transformLiquidsFinite(std::map<v3s16, MapBlock*> & modified_blocks)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -1625,6 +1645,365 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
        u32 loopcount = 0;
        u32 initial_size = m_transforming_liquid.size();
 
+       u8 relax = g_settings->getS16("liquid_relax");
+       bool fast_flood = g_settings->getS16("liquid_fast_flood");
+       int water_level = g_settings->getS16("water_level");
+
+       // list of nodes that due to viscosity have not reached their max level height
+       UniqueQueue<v3s16> must_reflow, must_reflow_second;
+
+       // List of MapBlocks that will require a lighting update (due to lava)
+       std::map<v3s16, MapBlock*> lighting_modified_blocks;
+
+       u16 loop_max = g_settings->getU16("liquid_loop_max");
+
+       //if (m_transforming_liquid.size() > 0) errorstream << "Liquid queue size="<<m_transforming_liquid.size()<<std::endl;
+
+       while (m_transforming_liquid.size() > 0)
+       {
+               // This should be done here so that it is done when continue is used
+               if (loopcount >= initial_size || loopcount >= loop_max)
+                       break;
+               loopcount++;
+               /*
+                       Get a queued transforming liquid node
+               */
+               v3s16 p0 = m_transforming_liquid.pop_front();
+               u16 total_level = 0;
+               // surrounding flowing liquid nodes
+               NodeNeighbor neighbors[7]; 
+               // current level of every block
+               s8 liquid_levels[7] = {-1, -1, -1, -1, -1, -1, -1};
+                // target levels
+               s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1};
+               s8 can_liquid_same_level = 0;
+               content_t liquid_kind = CONTENT_IGNORE;
+               content_t liquid_kind_flowing = CONTENT_IGNORE;
+               /*
+                       Collect information about the environment
+                */
+               const v3s16 *dirs = g_7dirs;
+               for (u16 i = 0; i < 7; i++) {
+                       NeighborType nt = NEIGHBOR_SAME_LEVEL;
+                       switch (i) {
+                               case D_TOP:
+                                       nt = NEIGHBOR_UPPER;
+                                       break;
+                               case D_BOTTOM:
+                                       nt = NEIGHBOR_LOWER;
+                                       break;
+                       }
+                       v3s16 npos = p0 + dirs[i];
+
+                       neighbors[i].n = getNodeNoEx(npos);
+                       neighbors[i].t = nt;
+                       neighbors[i].p = npos;
+                       neighbors[i].l = 0;
+                       neighbors[i].i = 0;
+                       NodeNeighbor & nb = neighbors[i];
+
+                       switch (nodemgr->get(nb.n.getContent()).liquid_type) {
+                               case LIQUID_NONE:
+                                       if (nb.n.getContent() == CONTENT_AIR) {
+                                               liquid_levels[i] = 0;
+                                               nb.l = 1;
+                                       }
+                                       break;
+                               case LIQUID_SOURCE:
+                                       // if this node is not (yet) of a liquid type,
+                                       // choose the first liquid type we encounter
+                                       if (liquid_kind_flowing == CONTENT_IGNORE)
+                                               liquid_kind_flowing = nodemgr->getId(
+                                                       nodemgr->get(nb.n).liquid_alternative_flowing);
+                                       if (liquid_kind == CONTENT_IGNORE)
+                                               liquid_kind = nb.n.getContent();
+                                       if (nb.n.getContent() == liquid_kind) {
+                                               liquid_levels[i] = nb.n.getLevel(nodemgr); //LIQUID_LEVEL_SOURCE;
+                                               nb.l = 1;
+                                               nb.i = (nb.n.param2 & LIQUID_INFINITY_MASK);
+                                       }
+                                       break;
+                               case LIQUID_FLOWING:
+                                       // if this node is not (yet) of a liquid type,
+                                       // choose the first liquid type we encounter
+                                       if (liquid_kind_flowing == CONTENT_IGNORE)
+                                               liquid_kind_flowing = nb.n.getContent();
+                                       if (liquid_kind == CONTENT_IGNORE)
+                                               liquid_kind = nodemgr->getId(
+                                                       nodemgr->get(nb.n).liquid_alternative_source);
+                                       if (nb.n.getContent() == liquid_kind_flowing) {
+                                               liquid_levels[i] = nb.n.getLevel(nodemgr); //(nb.n.param2 & LIQUID_LEVEL_MASK);
+                                               nb.l = 1;
+                                       }
+                                       break;
+                       }
+                       
+                       if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL)
+                               ++can_liquid_same_level;
+                       if (liquid_levels[i] > 0)
+                               total_level += liquid_levels[i];
+
+                       /*
+                       infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c="
+                       << nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1="
+                       << (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt="
+                       << nodemgr->get(nb.n.getContent()).liquid_type
+                       //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing
+                       << " l="<< nb.l << " inf="<< nb.i << " nlevel=" << (int)liquid_levels[i]
+                       << " tlevel=" << (int)total_level << " cansame="
+                       << (int)can_liquid_same_level << std::endl;
+                       */
+               }
+
+               if (liquid_kind == CONTENT_IGNORE ||
+                       !neighbors[D_SELF].l ||
+                       total_level <= 0)
+                       continue;
+
+               // fill bottom block
+               if (neighbors[D_BOTTOM].l) {
+                       liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ?
+                               LIQUID_LEVEL_SOURCE : total_level;
+                       total_level -= liquid_levels_want[D_BOTTOM];
+               }
+
+               //relax up
+               if (relax && ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) && liquid_levels[D_TOP] == 0 &&
+                       liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE &&
+                       total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level-
+                       (can_liquid_same_level - relax) &&
+                       can_liquid_same_level >= relax + 1) { 
+                       total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level; 
+               }
+
+               // prevent lakes in air above unloaded blocks
+               if (liquid_levels[D_TOP] == 0 && (p0.Y > water_level) && neighbors[D_BOTTOM].n.getContent() == CONTENT_IGNORE && !(loopcount % 3)) {
+                       --total_level;
+               }
+
+               // calculate self level 5 blocks
+               u8 want_level = 
+                         total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level
+                       ? LIQUID_LEVEL_SOURCE 
+                       : total_level / can_liquid_same_level;
+               total_level -= want_level * can_liquid_same_level;
+
+               //relax down
+               if (relax && p0.Y == water_level + 1 && liquid_levels[D_TOP] == 0 &&
+                       liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 &&
+                       total_level <= (can_liquid_same_level - relax) &&
+                       can_liquid_same_level >= relax + 1) {
+                       total_level = 0;
+               }
+
+               for (u16 ii = D_SELF; ii < D_TOP; ++ii) { // fill only same level
+                       if (!neighbors[ii].l)
+                               continue;
+                       liquid_levels_want[ii] = want_level;
+                       if (liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE && total_level > 0) {
+                               if (loopcount % 3 || liquid_levels[ii] <= 0){
+                                       if (liquid_levels[ii] > liquid_levels_want[ii]) {
+                                               ++liquid_levels_want[ii];
+                                               --total_level;
+                                       }
+                               } else if (neighbors[ii].l > 0){
+                                               ++liquid_levels_want[ii];
+                                               --total_level;
+                               }
+                       }
+               }
+
+               for (u16 ii = 0; ii < 7; ++ii) {
+                       if (total_level < 1) break;
+                       if (liquid_levels_want[ii] >= 0 &&
+                               liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE) {
+                               ++liquid_levels_want[ii];
+                               --total_level;
+                       }
+               }
+
+               // fill top block if can
+               if (neighbors[D_TOP].l) {
+                       liquid_levels_want[D_TOP] = total_level > LIQUID_LEVEL_SOURCE ?
+                               LIQUID_LEVEL_SOURCE : total_level;
+                       total_level -= liquid_levels_want[D_TOP];
+               }
+
+               for (u16 ii = 0; ii < 7; ii++) // infinity and cave flood optimization
+                       if (    neighbors[ii].i ||
+                               (liquid_levels_want[ii] >= 0 &&
+                                (fast_flood && p0.Y < water_level &&
+                                 (initial_size >= 1000
+                                  && ii != D_TOP
+                                  && want_level >= LIQUID_LEVEL_SOURCE/4
+                                  && can_liquid_same_level >= 5
+                                  && liquid_levels[D_TOP] >= LIQUID_LEVEL_SOURCE))))
+                               liquid_levels_want[ii] = LIQUID_LEVEL_SOURCE;
+
+               /*
+               if (total_level > 0) //|| flowed != volume)
+                       infostream <<" AFTER level=" << (int)total_level 
+                       //<< " flowed="<<flowed<< " volume=" << volume
+                       << " wantsame="<<(int)want_level<< " top="
+                       << (int)liquid_levels_want[D_TOP]<< " topwas="
+                       << (int)liquid_levels[D_TOP]<< " bot="
+                       << (int)liquid_levels_want[D_BOTTOM]<<std::endl;
+               */
+
+               //u8 changed = 0;
+               for (u16 i = 0; i < 7; i++) {
+                       if (liquid_levels_want[i] < 0 || !neighbors[i].l) 
+                               continue;
+                       MapNode & n0 = neighbors[i].n;
+                       p0 = neighbors[i].p;
+                       /*
+                               decide on the type (and possibly level) of the current node
+                       */
+                       content_t new_node_content;
+                       s8 new_node_level = -1;
+                       u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
+                       if (viscosity > 1 && liquid_levels_want[i] != liquid_levels[i]) {
+                               // amount to gain, limited by viscosity
+                               // must be at least 1 in absolute value
+                               s8 level_inc = liquid_levels_want[i] - liquid_levels[i];
+                               if (level_inc < -viscosity || level_inc > viscosity)
+                                       new_node_level = liquid_levels[i] + level_inc/viscosity;
+                               else if (level_inc < 0)
+                                       new_node_level = liquid_levels[i] - 1;
+                               else if (level_inc > 0)
+                                       new_node_level = liquid_levels[i] + 1;
+                       } else {
+                               new_node_level = liquid_levels_want[i];
+                       }
+                       
+                       if (new_node_level >= LIQUID_LEVEL_SOURCE)
+                               new_node_content = liquid_kind;
+                       else if (new_node_level > 0)
+                               new_node_content = liquid_kind_flowing;
+                       else
+                               new_node_content = CONTENT_AIR;
+                       
+                       // last level must flow down on stairs
+                       if (liquid_levels_want[i] != liquid_levels[i] &&
+                               liquid_levels[D_TOP] <= 0 && !neighbors[D_BOTTOM].l &&
+                               new_node_level >= 1 && new_node_level <= 2) {
+                               for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
+                                       if (neighbors[ii].l)
+                                               must_reflow_second.push_back(p0 + dirs[ii]);
+                               }
+                       }
+
+                       /*
+                               check if anything has changed.
+                               if not, just continue with the next node.
+                        */
+                       /*
+                       if (
+                                new_node_content == n0.getContent() 
+                               && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
+                                (n0.getLevel(nodemgr) == (u8)new_node_level
+                                //&& ((n0.param2 & LIQUID_FLOW_DOWN_MASK) ==
+                                //LIQUID_FLOW_DOWN_MASK) == flowing_down
+                                ))
+                               &&
+                                (nodemgr->get(n0.getContent()).liquid_type != LIQUID_SOURCE ||
+                                (((n0.param2 & LIQUID_INFINITY_MASK) ==
+                                       LIQUID_INFINITY_MASK) == neighbors[i].i
+                                ))
+                          )*/
+                       if (liquid_levels[i] == new_node_level)
+                       {
+                               continue;
+                       }
+                       
+                       //++changed;
+
+                       /*
+                               update the current node
+                        */
+                       /*
+                       if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
+                               // set level to last 3 bits, flowing down bit to 4th bit
+                               n0.param2 = (new_node_level & LIQUID_LEVEL_MASK);
+                       } else if (nodemgr->get(new_node_content).liquid_type == LIQUID_SOURCE) {
+                               //n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
+                               n0.param2 = (neighbors[i].i ? LIQUID_INFINITY_MASK : 0x00);
+                       }
+                       */
+                       /*
+                       infostream << "set node i=" <<(int)i<<" "<< PP(p0)<< " nc="
+                       <<new_node_content<< " p2="<<(int)n0.param2<< " nl="
+                       <<(int)new_node_level<<std::endl;
+                       */
+                       
+                       n0.setContent(liquid_kind_flowing);
+                       n0.setLevel(nodemgr, new_node_level);
+                       // Find out whether there is a suspect for this action
+                       std::string suspect;
+                       if(m_gamedef->rollback()){
+                               suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
+                       }
+
+                       if(!suspect.empty()){
+                               // Blame suspect
+                               RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
+                               // Get old node for rollback
+                               RollbackNode rollback_oldnode(this, p0, m_gamedef);
+                               // Set node
+                               setNode(p0, n0);
+                               // Report
+                               RollbackNode rollback_newnode(this, p0, m_gamedef);
+                               RollbackAction action;
+                               action.setSetNode(p0, rollback_oldnode, rollback_newnode);
+                               m_gamedef->rollback()->reportAction(action);
+                       } else {
+                               // Set node
+                               setNode(p0, n0);
+                       }
+
+                       v3s16 blockpos = getNodeBlockPos(p0);
+                       MapBlock *block = getBlockNoCreateNoEx(blockpos);
+                       if(block != NULL) {
+                               modified_blocks[blockpos] = block;
+                               // If node emits light, MapBlock requires lighting update
+                               if(nodemgr->get(n0).light_source != 0)
+                                       lighting_modified_blocks[block->getPos()] = block;
+                       }
+                       must_reflow.push_back(neighbors[i].p);
+               }
+               /* //for better relax  only same level
+               if (changed)  for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) {
+                       if (!neighbors[ii].l) continue;
+                       must_reflow.push_back(p0 + dirs[ii]);
+               }*/
+       }
+       /*
+       if (loopcount)
+               infostream<<"Map::transformLiquids(): loopcount="<<loopcount
+               <<" reflow="<<must_reflow.size()
+               <<" queue="<< m_transforming_liquid.size()<<std::endl;
+       */
+       while (must_reflow.size() > 0)
+               m_transforming_liquid.push_back(must_reflow.pop_front());
+       while (must_reflow_second.size() > 0)
+               m_transforming_liquid.push_back(must_reflow_second.pop_front());
+       updateLighting(lighting_modified_blocks, modified_blocks);
+}
+
+void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
+{
+
+       if (g_settings->getBool("liquid_finite"))
+               return Map::transformLiquidsFinite(modified_blocks);
+
+       INodeDefManager *nodemgr = m_gamedef->ndef();
+
+       DSTACK(__FUNCTION_NAME);
+       //TimeTaker timer("transformLiquids()");
+
+       u32 loopcount = 0;
+       u32 initial_size = m_transforming_liquid.size();
+
        /*if(initial_size != 0)
                infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
 
@@ -1632,12 +2011,14 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
        UniqueQueue<v3s16> must_reflow;
 
        // List of MapBlocks that will require a lighting update (due to lava)
-       core::map<v3s16, MapBlock*> lighting_modified_blocks;
+       std::map<v3s16, MapBlock*> lighting_modified_blocks;
+
+       u16 loop_max = g_settings->getU16("liquid_loop_max");
 
        while(m_transforming_liquid.size() != 0)
        {
                // This should be done here so that it is done when continue is used
-               if(loopcount >= initial_size || loopcount >= 10000)
+               if(loopcount >= initial_size || loopcount >= loop_max)
                        break;
                loopcount++;
 
@@ -1796,7 +2177,8 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                        } else
                                new_node_level = max_node_level;
 
-                       if (new_node_level >= 0)
+                       u8 range = rangelim(nodemgr->get(liquid_kind).liquid_range, 0, LIQUID_LEVEL_MAX+1);
+                       if (new_node_level >= (LIQUID_LEVEL_MAX+1-range))
                                new_node_content = liquid_kind;
                        else
                                new_node_content = CONTENT_AIR;
@@ -1816,6 +2198,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                /*
                        update the current node
                 */
+               MapNode n00 = n0;
                //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
                if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
                        // set level to last 3 bits, flowing down bit to 4th bit
@@ -1852,9 +2235,10 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                v3s16 blockpos = getNodeBlockPos(p0);
                MapBlock *block = getBlockNoCreateNoEx(blockpos);
                if(block != NULL) {
-                       modified_blocks.insert(blockpos, block);
-                       // If node emits light, MapBlock requires lighting update
-                       if(nodemgr->get(n0).light_source != 0)
+                       modified_blocks[blockpos] =  block;
+                       // If new or old node emits light, MapBlock requires lighting update
+                       if(nodemgr->get(n0).light_source != 0 ||
+                                       nodemgr->get(n00).light_source != 0)
                                lighting_modified_blocks[block->getPos()] = block;
                }
 
@@ -1991,6 +2375,26 @@ void Map::removeNodeTimer(v3s16 p)
        block->m_node_timers.remove(p_rel);
 }
 
+s16 Map::getHeat(v3s16 p)
+{
+       MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
+       if(block != NULL) {
+               return block->heat;
+       }
+       //errorstream << "No heat for " << p.X<<"," << p.Z << std::endl;
+       return 0;
+}
+
+s16 Map::getHumidity(v3s16 p)
+{
+       MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
+       if(block != NULL) {
+               return block->humidity;
+       }
+       //errorstream << "No humidity for " << p.X<<"," << p.Z << std::endl;
+       return 0;
+}
+
 /*
        ServerMap
 */
@@ -2008,15 +2412,15 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer
        m_mgparams = m_emerge->getParamsFromSettings(g_settings);
        if (!m_mgparams)
                m_mgparams = new MapgenV6Params();
-               
+
        m_seed = m_mgparams->seed;
 
        if (g_settings->get("fixed_map_seed").empty())
        {
-               m_seed = (((u64)(myrand()%0xffff)<<0)
-                               + ((u64)(myrand()%0xffff)<<16)
-                               + ((u64)(myrand()%0xffff)<<32)
-                               + ((u64)(myrand()&0xffff)<<48));
+               m_seed = (((u64)(myrand() & 0xffff) << 0)
+                               | ((u64)(myrand() & 0xffff) << 16)
+                               | ((u64)(myrand() & 0xffff) << 32)
+                               | ((u64)(myrand() & 0xffff) << 48));
                m_mgparams->seed = m_seed;
        }
 
@@ -2140,41 +2544,31 @@ ServerMap::~ServerMap()
                delete chunk;
        }
 #endif
+
+       delete m_mgparams;
 }
 
-void ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
+bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
 {
-       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;
+       bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
+       EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
 
-       //s16 chunksize = 3;
-       //v3s16 chunk_offset(-1,-1,-1);
-       //s16 chunksize = 4;
-       //v3s16 chunk_offset(-1,-1,-1);
-       s16 chunksize = 5;
-       v3s16 chunk_offset(-2,-2,-2);
+       s16 chunksize = m_mgparams->chunksize;
+       s16 coffset = -chunksize / 2;
+       v3s16 chunk_offset(coffset, coffset, coffset);
        v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
        v3s16 blockpos_min = blockpos_div * chunksize;
        v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
        blockpos_min += chunk_offset;
        blockpos_max += chunk_offset;
 
-       //v3s16 extra_borders(1,1,1);
        v3s16 extra_borders(1,1,1);
 
        // Do nothing if not inside limits (+-1 because of neighbors)
        if(blockpos_over_limit(blockpos_min - extra_borders) ||
                blockpos_over_limit(blockpos_max + extra_borders))
-       {
-               data->no_op = true;
-               return;
-       }
+               return false;
 
-       data->no_op = false;
        data->seed = m_seed;
        data->blockpos_min = blockpos_min;
        data->blockpos_max = blockpos_max;
@@ -2243,14 +2637,30 @@ void ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
        // Add the area
        {
                //TimeTaker timer("initBlockMake() initialEmerge");
-               data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
-       }
+               data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max, false);
+       }
+       
+       // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE
+/*     for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
+               for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
+                       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.
+       return true;
 }
 
 MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
-               core::map<v3s16, MapBlock*> &changed_blocks)
+               std::map<v3s16, MapBlock*> &changed_blocks)
 {
        v3s16 blockpos_min = data->blockpos_min;
        v3s16 blockpos_max = data->blockpos_max;
@@ -2261,13 +2671,7 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
 
        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);*/
@@ -2295,9 +2699,7 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
                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
@@ -2363,10 +2765,10 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
        /*
                Go through changed blocks
        */
-       for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
-                       i.atEnd() == false; i++)
+       for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
+                       i != changed_blocks.end(); ++i)
        {
-               MapBlock *block = i.getNode()->getValue();
+               MapBlock *block = i->second;
                assert(block);
                /*
                        Update day/night difference cache of the MapBlocks
@@ -2479,12 +2881,12 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
        sector = new ServerMapSector(this, p2d, m_gamedef);
 
        // Sector position on map in nodes
-       v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
+       //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
 
        /*
                Insert to container
        */
-       m_sectors.insert(p2d, sector);
+       m_sectors[p2d] = sector;
 
        return sector;
 }
@@ -2495,7 +2897,7 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
 */
 MapBlock * ServerMap::generateBlock(
                v3s16 p,
-               core::map<v3s16, MapBlock*> &modified_blocks
+               std::map<v3s16, MapBlock*> &modified_blocks
 )
 {
        DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
@@ -2695,7 +3097,7 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
        }
        /*if(allow_generate)
        {
-               core::map<v3s16, MapBlock*> modified_blocks;
+               std::map<v3s16, MapBlock*> modified_blocks;
                MapBlock *block = generateBlock(p, modified_blocks);
                if(block)
                {
@@ -2704,11 +3106,11 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
                        event.p = p;
 
                        // Copy modified_blocks to event
-                       for(core::map<v3s16, MapBlock*>::Iterator
-                                       i = modified_blocks.getIterator();
-                                       i.atEnd()==false; i++)
+                       for(std::map<v3s16, MapBlock*>::iterator
+                                       i = modified_blocks.begin();
+                                       i != modified_blocks.end(); ++i)
                        {
-                               event.modified_blocks.insert(i.getNode()->getKey(), false);
+                               event.modified_blocks.insert(i->first);
                        }
 
                        // Queue event
@@ -2876,17 +3278,18 @@ v2s16 ServerMap::getSectorPos(std::string dirname)
 {
        unsigned int x, y;
        int r;
-       size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
-       assert(spos != std::string::npos);
-       if(dirname.size() - spos == 8)
+       std::string component;
+       fs::RemoveLastPathComponent(dirname, &component, 1);
+       if(component.size() == 8)
        {
                // Old layout
-               r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
+               r = sscanf(component.c_str(), "%4x%4x", &x, &y);
        }
-       else if(dirname.size() - spos == 3)
+       else if(component.size() == 3)
        {
                // New layout
-               r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
+               fs::RemoveLastPathComponent(dirname, &component, 2);
+               r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
                // Sign-extend the 12 bit values up to 16 bits...
                if(x&0x800) x|=0xF000;
                if(y&0x800) y|=0xF000;
@@ -2949,10 +3352,10 @@ void ServerMap::save(ModifiedState save_level)
        // Don't do anything with sqlite unless something is really saved
        bool save_started = false;
 
-       core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
-       for(; i.atEnd() == false; i++)
+       for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
+               i != m_sectors.end(); ++i)
        {
-               ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
+               ServerMapSector *sector = (ServerMapSector*)i->second;
                assert(sector->getId() == MAPSECTOR_SERVER);
 
                if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
@@ -2960,17 +3363,17 @@ void ServerMap::save(ModifiedState save_level)
                        saveSectorMeta(sector);
                        sector_meta_count++;
                }
-               core::list<MapBlock*> blocks;
+               std::list<MapBlock*> blocks;
                sector->getBlocks(blocks);
-               core::list<MapBlock*>::Iterator j;
 
-               for(j=blocks.begin(); j!=blocks.end(); j++)
+               for(std::list<MapBlock*>::iterator j = blocks.begin();
+                       j != blocks.end(); ++j)
                {
                        MapBlock *block = *j;
 
                        block_count_all++;
 
-                       if(block->getModified() >= save_level)
+                       if(block->getModified() >= (u32)save_level)
                        {
                                // Lazy beginSave()
                                if(!save_started){
@@ -3037,7 +3440,7 @@ v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
        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 "
@@ -3057,6 +3460,26 @@ void ServerMap::listAllLoadableBlocks(core::list<v3s16> &dst)
        }
 }
 
+void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst)
+{
+       for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+               si != m_sectors.end(); ++si)
+       {
+               MapSector *sector = si->second;
+
+               std::list<MapBlock*> blocks;
+               sector->getBlocks(blocks);
+
+               for(std::list<MapBlock*>::iterator i = blocks.begin();
+                               i != blocks.end(); ++i)
+               {
+                       MapBlock *block = (*i);
+                       v3s16 p = block->getPos();
+                       dst.push_back(p);
+               }
+       }
+}
+
 void ServerMap::saveMapMeta()
 {
        DSTACK(__FUNCTION_NAME);
@@ -3068,27 +3491,21 @@ void ServerMap::saveMapMeta()
        createDirs(m_savedir);
 
        std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
-       std::ofstream os(fullpath.c_str(), std::ios_base::binary);
-       if(os.good() == false)
-       {
-               infostream<<"ERROR: ServerMap::saveMapMeta(): "
-                               <<"could not open"<<fullpath<<std::endl;
-               throw FileNotGoodException("Cannot open chunk metadata");
-       }
+       std::ostringstream ss(std::ios_base::binary);
 
        Settings params;
 
-       params.set("mg_name", m_emerge->params->mg_name);
-       params.setU64("seed", m_emerge->params->seed);
-       params.setS16("water_level", m_emerge->params->water_level);
-       params.setS16("chunksize", m_emerge->params->chunksize);
-       params.setS32("mg_flags", m_emerge->params->flags);
-
-       m_emerge->params->writeParams(&params);
+       m_emerge->setParamsToSettings(&params);
+       params.writeLines(ss);
 
-       params.writeLines(os);
+       ss<<"[end_of_params]\n";
 
-       os<<"[end_of_params]\n";
+       if(!fs::safeWriteToFile(fullpath, ss.str()))
+       {
+               infostream<<"ERROR: ServerMap::saveMapMeta(): "
+                               <<"could not write "<<fullpath<<std::endl;
+               throw FileNotGoodException("Cannot save chunk metadata");
+       }
 
        m_map_metadata_changed = false;
 }
@@ -3123,8 +3540,16 @@ void ServerMap::loadMapMeta()
                        break;
                params.parseConfigLine(line);
        }
-
-       MapgenParams *mgparams = m_emerge->getParamsFromSettings(&params);
+       
+       MapgenParams *mgparams;
+       try {
+               mgparams = m_emerge->getParamsFromSettings(&params);
+       } catch (SettingNotFoundException &e) {
+               infostream << "Couldn't get a setting from map_meta.txt: "
+                                  << e.what() << std::endl;
+               mgparams = NULL;
+       }
+       
        if (mgparams) {
                if (m_mgparams)
                        delete m_mgparams;
@@ -3144,18 +3569,19 @@ void ServerMap::saveSectorMeta(ServerMapSector *sector)
 {
        DSTACK(__FUNCTION_NAME);
        // Format used for writing
-       u8 version = SER_FMT_VER_HIGHEST;
+       u8 version = SER_FMT_VER_HIGHEST_WRITE;
        // Get destination
        v2s16 pos = sector->getPos();
        std::string dir = getSectorDir(pos);
        createDirs(dir);
 
        std::string fullpath = dir + DIR_DELIM + "meta";
-       std::ofstream o(fullpath.c_str(), std::ios_base::binary);
-       if(o.good() == false)
-               throw FileNotGoodException("Cannot open sector metafile");
+       std::ostringstream ss(std::ios_base::binary);
 
-       sector->serialize(o, version);
+       sector->serialize(ss, version);
+
+       if(!fs::safeWriteToFile(fullpath, ss.str()))
+               throw FileNotGoodException("Cannot write sector metafile");
 
        sector->differs_from_disk = false;
 }
@@ -3181,7 +3607,7 @@ MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load
                                        <<" Continuing with a sector with no metadata."
                                        <<std::endl;*/
                        sector = new ServerMapSector(this, p2d, m_gamedef);
-                       m_sectors.insert(p2d, sector);
+                       m_sectors[p2d] = sector;
                }
                else
                {
@@ -3343,7 +3769,7 @@ void ServerMap::saveBlock(MapBlock *block)
        }
 
        // Format used for writing
-       u8 version = SER_FMT_VER_HIGHEST;
+       u8 version = SER_FMT_VER_HIGHEST_WRITE;
        // Get destination
        v3s16 p3d = block->getPos();
 
@@ -3451,7 +3877,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
                        Save blocks loaded in old format in new format
                */
 
-               if(version < SER_FMT_VER_HIGHEST || save_after_load)
+               if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
                {
                        saveBlock(block);
 
@@ -3470,7 +3896,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
                                <<" (SerializationError). "
                                <<"what()="<<e.what()
                                <<std::endl;
-                               //" Ignoring. A new one will be generated.
+                               // Ignoring. A new one will be generated.
                assert(0);
 
                // TODO: Backup file; name is in fullpath.
@@ -3518,7 +3944,7 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
                        Save blocks loaded in old format in new format
                */
 
-               //if(version < SER_FMT_VER_HIGHEST || save_after_load)
+               //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
                // Only save if asked to; no need to update version
                if(save_after_load)
                        saveBlock(block);
@@ -3646,6 +4072,63 @@ void ServerMap::PrintInfo(std::ostream &out)
        out<<"ServerMap: ";
 }
 
+s16 ServerMap::getHeat(ServerEnvironment *env, v3s16 p, MapBlock *block)
+{
+       if(block == NULL)
+               block = getBlockNoCreateNoEx(getNodeBlockPos(p));
+       if(block != NULL) {
+               if (env->getGameTime() - block->heat_time < 10)
+                       return block->heat;
+       }
+
+       //variant 1: full random
+       //f32 heat = NoisePerlin3D(m_emerge->biomedef->np_heat, p.X, env->getGameTime()/100, p.Z, m_emerge->params->seed);
+
+       //variant 2: season change based on default heat map
+       f32 heat = NoisePerlin2D(m_emerge->biomedef->np_heat, p.X, p.Z, m_emerge->params->seed);
+       heat += -30; // -30 - todo REMOVE after fixed NoiseParams nparams_biome_def_heat = {50, 50, -> 20, 50,
+       f32 base = (f32)env->getGameTime() * env->getTimeOfDaySpeed();
+       base /= ( 86400 * g_settings->getS16("year_days") );
+       base += (f32)p.X / 3000;
+       heat += 30 * sin(base * M_PI); // season
+
+       heat += p.Y / -333; // upper=colder, lower=hotter
+
+       // daily change, hotter at sun +4, colder at night -4
+       heat += 8 * (sin(cycle_shift(env->getTimeOfDayF(), -0.25) * M_PI) - 0.5); 
+
+       if(block != NULL) {
+               block->heat = heat;
+               block->heat_time = env->getGameTime();
+       }
+       return heat;
+}
+
+s16 ServerMap::getHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block)
+{
+       if(block == NULL)
+               block = getBlockNoCreateNoEx(getNodeBlockPos(p));
+       if(block != NULL) {
+               if (env->getGameTime() - block->humidity_time < 10)
+                       return block->humidity;
+       }
+
+       f32 humidity = NoisePerlin3D(   m_emerge->biomedef->np_humidity,
+                                       p.X, env->getGameTime()/10, p.Z,
+                                       m_emerge->params->seed);
+       humidity += -12 * ( sin(cycle_shift(env->getTimeOfDayF(), -0.1) * M_PI) - 0.5);
+       //todo like heat//humidity += 20 * ( sin(((f32)p.Z / 300) * M_PI) - 0.5);
+
+       if (humidity > 100) humidity = 100;
+       if (humidity < 0) humidity = 0;
+
+       if(block != NULL) {
+               block->humidity = humidity;
+               block->humidity_time = env->getGameTime();
+       }
+       return humidity;
+}
+
 /*
        MapVoxelManipulator
 */
@@ -3678,10 +4161,12 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
        for(s32 y=p_min.Y; y<=p_max.Y; y++)
        for(s32 x=p_min.X; x<=p_max.X; x++)
        {
+               u8 flags = 0;
+               MapBlock *block;
                v3s16 p(x,y,z);
-               core::map<v3s16, bool>::Node *n;
+               std::map<v3s16, u8>::iterator n;
                n = m_loaded_blocks.find(p);
-               if(n != NULL)
+               if(n != m_loaded_blocks.end())
                        continue;
 
                bool block_data_inexistent = false;
@@ -3695,7 +4180,7 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
                        a.print(infostream);
                        infostream<<std::endl;*/
 
-                       MapBlock *block = m_map->getBlockNoCreate(p);
+                       block = m_map->getBlockNoCreate(p);
                        if(block->isDummy())
                                block_data_inexistent = true;
                        else
@@ -3708,6 +4193,8 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
 
                if(block_data_inexistent)
                {
+                       flags |= VMANIP_BLOCK_DATA_INEXIST;
+
                        VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
                        // Fill with VOXELFLAG_INEXISTENT
                        for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
@@ -3717,8 +4204,13 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
                                memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
                        }
                }
+               /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
+               {
+                       // Mark that block was loaded as blank
+                       flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
+               }*/
 
-               m_loaded_blocks.insert(p, !block_data_inexistent);
+               m_loaded_blocks[p] = flags;
        }
 
        //infostream<<"emerge done"<<std::endl;
@@ -3730,7 +4222,7 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
                  run on background.
 */
 void MapVoxelManipulator::blitBack
-               (core::map<v3s16, MapBlock*> & modified_blocks)
+               (std::map<v3s16, MapBlock*> & modified_blocks)
 {
        if(m_area.getExtent() == v3s16(0,0,0))
                return;
@@ -3811,8 +4303,8 @@ void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
        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);
 
@@ -3838,10 +4330,12 @@ 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++)
        {
+               u8 flags = 0;
+               MapBlock *block;
                v3s16 p(x,y,z);
-               core::map<v3s16, bool>::Node *n;
+               std::map<v3s16, u8>::iterator n;
                n = m_loaded_blocks.find(p);
-               if(n != NULL)
+               if(n != m_loaded_blocks.end())
                        continue;
 
                bool block_data_inexistent = false;
@@ -3849,7 +4343,7 @@ void ManualMapVoxelManipulator::initialEmerge(
                {
                        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
@@ -3862,25 +4356,42 @@ void ManualMapVoxelManipulator::initialEmerge(
 
                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_INEXISTENT
+                               for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
+                               for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
+                               {
+                                       s32 i = m_area.index(a.MinEdge.X,y,z);
+                                       memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
+                               }
                        }
                }
+               /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
+               {
+                       // Mark that block was loaded as blank
+                       flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
+               }*/
 
-               m_loaded_blocks.insert(p, !block_data_inexistent);
+               m_loaded_blocks[p] = flags;
        }
 }
 
 void ManualMapVoxelManipulator::blitBackAll(
-               core::map<v3s16, MapBlock*> * modified_blocks)
+               std::map<v3s16, MapBlock*> * modified_blocks)
 {
        if(m_area.getExtent() == v3s16(0,0,0))
                return;
@@ -3888,34 +4399,22 @@ void ManualMapVoxelManipulator::blitBackAll(
        /*
                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);
-               if(block == NULL)
+               bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
+               if(existed == false)
                {
-                       infostream<<"WARNING: "<<__FUNCTION_NAME
-                                       <<": got NULL block "
-                                       <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
-                                       <<std::endl;
                        continue;
                }
 
                block->copyFrom(*this);
 
                if(modified_blocks)
-                       modified_blocks->insert(p, block);
+                       (*modified_blocks)[p] = block;
        }
 }