]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/map.cpp
Fix most warnings, re-fix MSVC compile error
[dragonfireclient.git] / src / map.cpp
index ab9cb25dd20b97b37cb76db7379c42ecd0f1e408..4be094326f182e47243699107f704cbfa96876ef 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
@@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "gamedef.h"
 #include "util/directiontables.h"
 #include "rollback_interface.h"
+#include "emerge.h"
 #include "mapgen_v6.h"
 
 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
@@ -1613,10 +1614,322 @@ 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
+};
+
+#define D_BOTTOM 0
+#define D_TOP 6
+#define D_SELF 1
+
+void Map::transformLiquidsFinite(core::map<v3s16, MapBlock*> & modified_blocks)
+{
+       INodeDefManager *nodemgr = m_gamedef->ndef();
+
+       DSTACK(__FUNCTION_NAME);
+       //TimeTaker timer("transformLiquids()");
+
+       u32 loopcount = 0;
+       u32 initial_size = m_transforming_liquid.size();
+
+       u8 relax = g_settings->getS16("liquid_relax");
+       bool fast_flood = g_settings->getS16("liquid_fast_flood");
+       int water_level = g_settings->getS16("water_level");
+
+       /*if(initial_size != 0)
+               infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
+
+       // list of nodes that due to viscosity have not reached their max level height
+       UniqueQueue<v3s16> must_reflow, must_reflow_second;
+
+       // List of MapBlocks that will require a lighting update (due to lava)
+       core::map<v3s16, MapBlock*> lighting_modified_blocks;
+
+       while(m_transforming_liquid.size() > 0)
+       {
+               // This should be done here so that it is done when continue is used
+               if(loopcount >= initial_size || loopcount >= 1000)
+                       break;
+               loopcount++;
+               /*
+                       Get a queued transforming liquid node
+               */
+               v3s16 p0 = m_transforming_liquid.pop_front();
+               u16 total_level = 0;
+               NodeNeighbor neighbors[7]; // surrounding flowing liquid nodes
+               s8 liquid_levels[7]      = {-1, -1, -1, -1, -1, -1, -1}; // current level of every block
+               s8 liquid_levels_want[7] = {-1, -1, -1, -1, -1, -1, -1}; // target levels
+               s8 can_liquid_same_level = 0;
+               content_t liquid_kind = CONTENT_IGNORE;
+               content_t liquid_kind_flowing = CONTENT_IGNORE;
+               /*
+                       Collect information about the environment
+                */
+               const v3s16 *dirs = g_7dirs;
+               for (u16 i = 0; i < 7; i++) {
+                       NeighborType nt = NEIGHBOR_SAME_LEVEL;
+                       switch (i) {
+                               case D_TOP:
+                                       nt = NEIGHBOR_UPPER;
+                                       break;
+                               case D_BOTTOM:
+                                       nt = NEIGHBOR_LOWER;
+                                       break;
+                       }
+                       v3s16 npos = p0 + dirs[i];
+
+                       neighbors[i].n = getNodeNoEx(npos);
+                       neighbors[i].t = nt;
+                       neighbors[i].p = npos;
+                       neighbors[i].l = 0;
+                       neighbors[i].i = 0;
+                       NodeNeighbor & nb = neighbors[i];
+
+                       switch (nodemgr->get(nb.n.getContent()).liquid_type) {
+                               case LIQUID_NONE:
+                                       if (nb.n.getContent() == CONTENT_AIR) {
+                                               liquid_levels[i] = 0;
+                                               nb.l = 1;
+                                       }
+                                       break;
+                               case LIQUID_SOURCE:
+                                       // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
+                                       if (liquid_kind_flowing == CONTENT_IGNORE)
+                                               liquid_kind_flowing = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
+                                       if (liquid_kind == CONTENT_IGNORE)
+                                               liquid_kind = nb.n.getContent();
+                                       if (nb.n.getContent() == liquid_kind) {
+                                               liquid_levels[i] = LIQUID_LEVEL_SOURCE;
+                                               nb.l = 1;
+                                               nb.i = (nb.n.param2 & LIQUID_INFINITY_MASK);
+                                       }
+                                       break;
+                               case LIQUID_FLOWING:
+                                       // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
+                                       if (liquid_kind_flowing == CONTENT_IGNORE)
+                                               liquid_kind_flowing = nb.n.getContent();
+                                       if (liquid_kind == CONTENT_IGNORE)
+                                               liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_source);
+                                       if (nb.n.getContent() == liquid_kind_flowing) {
+                                               liquid_levels[i] = (nb.n.param2 & LIQUID_LEVEL_MASK);
+                                               nb.l = 1;
+                                       }
+                                       break;
+                       }
+                       if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL) ++can_liquid_same_level;
+                       if (liquid_levels[i] > 0) total_level += liquid_levels[i];
+
+                       /*
+                       infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c="<<nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1="<< (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt="<<nodemgr->get(nb.n.getContent()).liquid_type
+                       //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing
+                       << " l="<< nb.l << " inf="<< nb.i << " nlevel=" <<  (int)liquid_levels[i] << " tlevel=" << (int)total_level << " cansame="<<(int)can_liquid_same_level<<std::endl;
+                       */
+               }
+
+               if (liquid_kind == CONTENT_IGNORE || !neighbors[D_SELF].l || total_level <= 0)
+                       continue;
+
+               // fill bottom block
+               if (neighbors[D_BOTTOM].l) {
+                       liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ? LIQUID_LEVEL_SOURCE : total_level;
+                       total_level -= liquid_levels_want[D_BOTTOM];
+               }
+
+               if (relax && p0.Y <= water_level && liquid_levels[D_TOP] == 0 && total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level - can_liquid_same_level + 2 && can_liquid_same_level >= relax + 1) { //relax up
+                       total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level; 
+               }
+
+               // calculate self level 5 blocks
+               u8 want_level = 
+                         total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level
+                       ? LIQUID_LEVEL_SOURCE 
+                       : total_level / can_liquid_same_level;
+               total_level -= want_level * can_liquid_same_level;
+
+               if (relax && p0.Y > water_level && liquid_levels[D_TOP] == 0 && liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && want_level == 0 && total_level <= can_liquid_same_level - 2 && can_liquid_same_level >= relax + 1) { //relax down
+                       total_level = 0;
+               }
+
+               for (u16 ii = D_SELF; ii < D_TOP; ++ii) { // fill only same level
+                       if (!neighbors[ii].l)
+                               continue;
+                       liquid_levels_want[ii] = want_level;
+                       if (liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE && total_level > 0
+                               && liquid_levels[ii] > liquid_levels_want[ii]
+                               ) {
+                               ++liquid_levels_want[ii];
+                               --total_level;
+                       }
+               }
+
+               for (u16 ii = 0; ii < 7; ++ii) {
+                       if (total_level < 1) break;
+                       if (liquid_levels_want[ii] >= 0 && liquid_levels_want[ii] < LIQUID_LEVEL_SOURCE) {
+                               ++liquid_levels_want[ii];
+                               --total_level;
+                       }
+               }
+
+               // fill top block if can
+               if (neighbors[D_TOP].l) {
+                       liquid_levels_want[D_TOP] = total_level > LIQUID_LEVEL_SOURCE ? LIQUID_LEVEL_SOURCE : total_level ;
+                       total_level -= liquid_levels_want[D_TOP];
+               }
+
+               for (u16 ii = 0; ii < 7; ii++) // infinity and cave flood optimization
+                       if (liquid_levels_want[ii] >= 0 &&
+                               (neighbors[ii].i ||
+                                (fast_flood && p0.Y < water_level &&
+                                 (initial_size >= 1000
+                                  && ii != D_TOP
+                                  && want_level >= LIQUID_LEVEL_SOURCE/4
+                                  && can_liquid_same_level >= 5
+                                  && liquid_levels[D_TOP] >= LIQUID_LEVEL_SOURCE))))
+                               liquid_levels_want[ii] = LIQUID_LEVEL_SOURCE;
+
+               //if (total_level > 0 /*|| flowed != volume*/) infostream <<" AFTER level=" << (int)total_level /*<< " flowed="<<flowed<< " volume=" <<volume*/<< " wantsame="<<(int)want_level<< " top="<< (int)liquid_levels_want[D_TOP]<< " topwas="<< (int)liquid_levels[D_TOP]<< " bot="<< (int)liquid_levels_want[D_BOTTOM]<<std::endl;
+
+               u8 changed = 0;
+               for (u16 i = 0; i < 7; i++) {
+                       if (liquid_levels_want[i] < 0 || !neighbors[i].l) 
+                               continue;
+                       MapNode & n0 = neighbors[i].n;
+                       p0 = neighbors[i].p;
+                       /*
+                               decide on the type (and possibly level) of the current node
+                       */
+                       content_t new_node_content;
+                       s8 new_node_level = -1;
+                       u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
+                       if (viscosity > 1 && liquid_levels_want[i] != liquid_levels[i]) {
+                               // amount to gain, limited by viscosity
+                               // must be at least 1 in absolute value
+                               s8 level_inc = liquid_levels_want[i] - liquid_levels[i];
+                               if (level_inc < -viscosity || level_inc > viscosity)
+                                       new_node_level = liquid_levels[i] + level_inc/viscosity;
+                               else if (level_inc < 0)
+                                       new_node_level = liquid_levels[i] - 1;
+                               else if (level_inc > 0)
+                                       new_node_level = liquid_levels[i] + 1;
+                       } else
+                               new_node_level = liquid_levels_want[i];
+                       if (new_node_level >= LIQUID_LEVEL_SOURCE)
+                               new_node_content = liquid_kind;
+                       else if (new_node_level > 0)
+                               new_node_content = liquid_kind_flowing;
+                       else
+                               new_node_content = CONTENT_AIR;
+
+                       // last level must flow down on stairs
+                       if (liquid_levels_want[i] != liquid_levels[i] && liquid_levels[D_TOP] <= 0 && !neighbors[D_BOTTOM].l && new_node_level >= 1 && new_node_level <= 2) //maybe == 1 // 
+                               for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
+                               if (!neighbors[ii].l)
+                                       continue;
+                               must_reflow_second.push_back(p0 + dirs[ii]);
+                       }
+
+                       /*
+                               check if anything has changed. if not, just continue with the next node.
+                        */
+                       if (
+                                new_node_content == n0.getContent() 
+                               && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
+                                ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level 
+                                // &&((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)== flowing_down
+                                ))
+                               &&
+                                (nodemgr->get(n0.getContent()).liquid_type != LIQUID_SOURCE ||
+                                (((n0.param2 & LIQUID_INFINITY_MASK) == LIQUID_INFINITY_MASK) == neighbors[i].i
+                                ))
+                          ) {
+                               continue;
+                       }
+                       ++changed;
+
+                       /*
+                               update the current node
+                        */
+                       if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
+                               // set level to last 3 bits, flowing down bit to 4th bit
+                               n0.param2 = (new_node_level & LIQUID_LEVEL_MASK);
+                       } else if (nodemgr->get(new_node_content).liquid_type == LIQUID_SOURCE) {
+                               //n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
+                               n0.param2 = (neighbors[i].i ? LIQUID_INFINITY_MASK : 0x00);
+                       }
+                       //infostream << "set node i=" <<(int)i<<" "<< PP(p0)<< " nc="<<new_node_content<< " p2="<<(int)n0.param2<< " nl="<<(int)new_node_level<<std::endl;
+                       n0.setContent(new_node_content);
+                       // Find out whether there is a suspect for this action
+                       std::string suspect;
+                       if(m_gamedef->rollback()){
+                               suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
+                       }
+
+                       if(!suspect.empty()){
+                               // Blame suspect
+                               RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
+                               // Get old node for rollback
+                               RollbackNode rollback_oldnode(this, p0, m_gamedef);
+                               // Set node
+                               setNode(p0, n0);
+                               // Report
+                               RollbackNode rollback_newnode(this, p0, m_gamedef);
+                               RollbackAction action;
+                               action.setSetNode(p0, rollback_oldnode, rollback_newnode);
+                               m_gamedef->rollback()->reportAction(action);
+                       } else {
+                               // Set node
+                               setNode(p0, n0);
+                       }
+
+                       v3s16 blockpos = getNodeBlockPos(p0);
+                       MapBlock *block = getBlockNoCreateNoEx(blockpos);
+                       if(block != NULL) {
+                               modified_blocks.insert(blockpos, block);
+                               // If node emits light, MapBlock requires lighting update
+                               if(nodemgr->get(n0).light_source != 0)
+                                       lighting_modified_blocks[block->getPos()] = block;
+                       }
+                       must_reflow.push_back(neighbors[i].p);
+               }
+               /* //for better relax
+               if (changed)  for (u16 ii = D_SELF + 1; ii < D_TOP; ++ii) { // only same level
+                       if (!neighbors[ii].l) continue;
+                       must_reflow.push_back(p0 + dirs[ii]);
+               }*/
+       }
+       //if (loopcount) infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<" reflow="<<must_reflow.size()<<" queue="<< m_transforming_liquid.size()<<std::endl;
+       while (must_reflow.size() > 0)
+               m_transforming_liquid.push_back(must_reflow.pop_front());
+       while (must_reflow_second.size() > 0)
+               m_transforming_liquid.push_back(must_reflow_second.pop_front());
+       updateLighting(lighting_modified_blocks, modified_blocks);
+}
+
 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
 {
+
+       if (g_settings->getBool("liquid_finite")) return Map::transformLiquidsFinite(modified_blocks);
+       
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
        DSTACK(__FUNCTION_NAME);
@@ -2008,7 +2321,7 @@ 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())
@@ -2142,14 +2455,10 @@ ServerMap::~ServerMap()
 #endif
 }
 
-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);
@@ -2169,12 +2478,8 @@ void ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
        // 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;
@@ -2245,8 +2550,24 @@ void ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
                //TimeTaker timer("initBlockMake() initialEmerge");
                data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
        }
+       
+       // 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,
@@ -2261,13 +2582,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 +2610,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
@@ -2970,7 +3283,7 @@ void ServerMap::save(ModifiedState save_level)
 
                        block_count_all++;
 
-                       if(block->getModified() >= save_level)
+                       if(block->getModified() >= (u32)save_level)
                        {
                                // Lazy beginSave()
                                if(!save_started){
@@ -3078,14 +3391,7 @@ void ServerMap::saveMapMeta()
 
        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(os);
 
        os<<"[end_of_params]\n";
@@ -3678,8 +3984,10 @@ 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;
+               core::map<v3s16, u8>::Node *n;
                n = m_loaded_blocks.find(p);
                if(n != NULL)
                        continue;
@@ -3695,7 +4003,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 +4016,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 +4027,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.insert(p, flags);
        }
 
        //infostream<<"emerge done"<<std::endl;
@@ -3838,8 +4153,10 @@ 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;
+               core::map<v3s16, u8>::Node *n;
                n = m_loaded_blocks.find(p);
                if(n != NULL)
                        continue;
@@ -3849,7 +4166,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,6 +4179,8 @@ void ManualMapVoxelManipulator::initialEmerge(
 
                if(block_data_inexistent)
                {
+                       flags |= VMANIP_BLOCK_DATA_INEXIST;
+                       
                        /*
                                Mark area inexistent
                        */
@@ -3874,8 +4193,13 @@ void ManualMapVoxelManipulator::initialEmerge(
                                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.insert(p, flags);
        }
 }
 
@@ -3888,12 +4212,14 @@ void ManualMapVoxelManipulator::blitBackAll(
        /*
                Copy data of all blocks
        */
-       for(core::map<v3s16, bool>::Iterator
+       for(core::map<v3s16, u8>::Iterator
                        i = m_loaded_blocks.getIterator();
                        i.atEnd() == false; i++)
        {
                v3s16 p = i.getNode()->getKey();
-               bool existed = i.getNode()->getValue();
+               u8 flags = i.getNode()->getValue();
+               
+               bool existed = !(flags & VMANIP_BLOCK_DATA_INEXIST);
                if(existed == false)
                {
                        // The Great Bug was found using this
@@ -3902,6 +4228,7 @@ void ManualMapVoxelManipulator::blitBackAll(
                                        <<std::endl;*/
                        continue;
                }
+               
                MapBlock *block = m_map->getBlockNoCreateNoEx(p);
                if(block == NULL)
                {
@@ -3913,7 +4240,7 @@ void ManualMapVoxelManipulator::blitBackAll(
                }
 
                block->copyFrom(*this);
-
+               
                if(modified_blocks)
                        modified_blocks->insert(p, block);
        }