X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmap.cpp;h=4b0d2e2d8e846d8e5ee664ece1e245a8e4b4faaa;hb=5da6896d51ae3ee5140dc1041eff44a616751231;hp=cf7dd6f9fd94fef1e9b6febffe1d3c93d1af0d44;hpb=2c0b51795e6fa6747d881f1871c89830abb6e6e8;p=dragonfireclient.git diff --git a/src/map.cpp b/src/map.cpp index cf7dd6f9f..4b0d2e2d8 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "voxel.h" #include "porting.h" -#include "mapgen.h" +#include "serialization.h" #include "nodemetadata.h" #include "settings.h" #include "log.h" @@ -32,10 +32,23 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "gamedef.h" #include "util/directiontables.h" +#include "util/mathconstants.h" #include "rollback_interface.h" +#include "environment.h" #include "emerge.h" #include "mapgen_v6.h" -#include "mapgen_indev.h" +#include "mg_biome.h" +#include "config.h" +#include "server.h" +#include "database.h" +#include "database-dummy.h" +#include "database-sqlite3.h" +#if USE_LEVELDB +#include "database-leveldb.h" +#endif +#if USE_REDIS +#include "database-redis.h" +#endif #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")" @@ -65,8 +78,6 @@ Map::Map(std::ostream &dout, IGameDef *gamedef): m_gamedef(gamedef), m_sector_cache(NULL) { - /*m_sector_mutex.Init(); - assert(m_sector_mutex.IsInitialized());*/ } Map::~Map() @@ -175,26 +186,42 @@ bool Map::isValidPosition(v3s16 p) } // Returns a CONTENT_IGNORE node if not found -MapNode Map::getNodeNoEx(v3s16 p) +MapNode Map::getNodeNoEx(v3s16 p, bool *is_valid_position) { v3s16 blockpos = getNodeBlockPos(p); MapBlock *block = getBlockNoCreateNoEx(blockpos); - if(block == NULL) + if (block == NULL) { + if (is_valid_position != NULL) + *is_valid_position = false; return MapNode(CONTENT_IGNORE); + } + v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; - return block->getNodeNoCheck(relpos); + bool is_valid_p; + MapNode node = block->getNodeNoCheck(relpos, &is_valid_p); + if (is_valid_position != NULL) + *is_valid_position = is_valid_p; + return node; } +#if 0 +// Deprecated // throws InvalidPositionException if not found +// TODO: Now this is deprecated, getNodeNoEx should be renamed MapNode Map::getNode(v3s16 p) { v3s16 blockpos = getNodeBlockPos(p); MapBlock *block = getBlockNoCreateNoEx(blockpos); - if(block == NULL) + if (block == NULL) throw InvalidPositionException(); v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; - return block->getNodeNoCheck(relpos); + bool is_valid_position; + MapNode node = block->getNodeNoCheck(relpos, &is_valid_position); + if (!is_valid_position) + throw InvalidPositionException(); + return node; } +#endif // throws InvalidPositionException if not found void Map::setNode(v3s16 p, MapNode & n) @@ -204,9 +231,10 @@ void Map::setNode(v3s16 p, MapNode & n) v3s16 relpos = p - blockpos*MAP_BLOCKSIZE; // Never allow placing CONTENT_IGNORE, it fucks up stuff if(n.getContent() == CONTENT_IGNORE){ + bool temp_bool; errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE" <<" while trying to replace \"" - <ndef()->get(block->getNodeNoCheck(relpos)).name + <ndef()->get(block->getNodeNoCheck(relpos, &temp_bool)).name <<"\" at "<getNode(relpos); + // Calculate relative position in block + v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE; + // Get node straight from the block + bool is_valid_position; + MapNode n2 = block->getNode(relpos, &is_valid_position); + if (!is_valid_position) + continue; - bool changed = false; + bool changed = false; - //TODO: Optimize output by optimizing light_sources? + //TODO: Optimize output by optimizing light_sources? + /* + If the neighbor is dimmer than what was specified + as oldlight (the light of the previous node) + */ + if(n2.getLight(bank, nodemgr) < oldlight) + { /* - If the neighbor is dimmer than what was specified - as oldlight (the light of the previous node) + And the neighbor is transparent and it has some light */ - if(n2.getLight(bank, nodemgr) < oldlight) + if(nodemgr->get(n2).light_propagates + && n2.getLight(bank, nodemgr) != 0) { /* - And the neighbor is transparent and it has some light + Set light to 0 and add to queue */ - if(nodemgr->get(n2).light_propagates - && n2.getLight(bank, nodemgr) != 0) - { - /* - Set light to 0 and add to queue - */ - - u8 current_light = n2.getLight(bank, nodemgr); - n2.setLight(bank, 0, nodemgr); - block->setNode(relpos, n2); - - unlighted_nodes[n2pos] = current_light; - changed = true; - - /* - Remove from light_sources if it is there - NOTE: This doesn't happen nearly at all - */ - /*if(light_sources.find(n2pos)) - { - infostream<<"Removed from light_sources"<setNode(relpos, n2); - // 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) == modified_blocks.end()) + unlighted_nodes[n2pos] = current_light; + changed = true; + + /* + Remove from light_sources if it is there + NOTE: This doesn't happen nearly at all + */ + /*if(light_sources.find(n2pos)) { - modified_blocks[blockpos] = block; - } - block_checked_in_modified = true; + infostream<<"Removed from light_sources"<getNode(relpos); + bool is_valid_position; + MapNode n = block->getNode(relpos, &is_valid_position); - u8 oldlight = n.getLight(bank, nodemgr); + u8 oldlight = is_valid_position ? n.getLight(bank, nodemgr) : 0; u8 newlight = diminish_light(oldlight); // Loop through 6 neighbors @@ -488,67 +511,61 @@ void Map::spreadLight(enum LightBank bank, // Get the block where the node is located v3s16 blockpos = getNodeBlockPos(n2pos); - try - { - // Only fetch a new block if the block position has changed - try{ - if(block == NULL || blockpos != blockpos_last){ - block = getBlockNoCreate(blockpos); - blockpos_last = blockpos; + // Only fetch a new block if the block position has changed + try { + if(block == NULL || blockpos != blockpos_last){ + block = getBlockNoCreate(blockpos); + blockpos_last = blockpos; - block_checked_in_modified = false; - blockchangecount++; - } - } - catch(InvalidPositionException &e) - { - continue; + block_checked_in_modified = false; + blockchangecount++; } + } + catch(InvalidPositionException &e) { + continue; + } - // Calculate relative position in block - v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE; - // Get node straight from the block - MapNode n2 = block->getNode(relpos); + // Calculate relative position in block + v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE; + // Get node straight from the block + MapNode n2 = block->getNode(relpos, &is_valid_position); + if (!is_valid_position) + continue; - bool changed = false; - /* - If the neighbor is brighter than the current node, - add to list (it will light up this node on its turn) - */ - if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight)) + bool changed = false; + /* + If the neighbor is brighter than the current node, + add to list (it will light up this node on its turn) + */ + if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight)) + { + lighted_nodes.insert(n2pos); + changed = true; + } + /* + If the neighbor is dimmer than how much light this node + would spread on it, add to list + */ + if(n2.getLight(bank, nodemgr) < newlight) + { + if(nodemgr->get(n2).light_propagates) { + n2.setLight(bank, newlight, nodemgr); + block->setNode(relpos, n2); lighted_nodes.insert(n2pos); changed = true; } - /* - If the neighbor is dimmer than how much light this node - would spread on it, add to list - */ - if(n2.getLight(bank, nodemgr) < newlight) - { - if(nodemgr->get(n2).light_propagates) - { - n2.setLight(bank, newlight, nodemgr); - block->setNode(relpos, n2); - lighted_nodes.insert(n2pos); - changed = true; - } - } + } - // Add to modified_blocks - if(changed == true && block_checked_in_modified == false) + // 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) == modified_blocks.end()) { - // If the block is not found in modified_blocks, add. - if(modified_blocks.find(blockpos) == modified_blocks.end()) - { - modified_blocks[blockpos] = block; - } - block_checked_in_modified = true; + modified_blocks[blockpos] = block; } - } - catch(InvalidPositionException &e) - { - continue; + block_checked_in_modified = true; } } } @@ -596,13 +613,11 @@ v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p) // Get the position of the neighbor node v3s16 n2pos = p + dirs[i]; MapNode n2; - try{ - n2 = getNode(n2pos); - } - catch(InvalidPositionException &e) - { + bool is_valid_position; + n2 = getNodeNoEx(n2pos, &is_valid_position); + if (!is_valid_position) continue; - } + if(n2.getLight(bank, nodemgr) > brightest_light || found_something == false){ brightest_light = n2.getLight(bank, nodemgr); brightest_pos = n2pos; @@ -645,7 +660,10 @@ s16 Map::propagateSunlight(v3s16 start, } v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE; - MapNode n = block->getNode(relpos); + bool is_valid_position; + MapNode n = block->getNode(relpos, &is_valid_position); + if (!is_valid_position) + break; if(nodemgr->get(n).sunlight_propagates) { @@ -712,39 +730,37 @@ void Map::updateLighting(enum LightBank bank, for(s16 x=0; xgetNode(p); - u8 oldlight = n.getLight(bank, nodemgr); - n.setLight(bank, 0, nodemgr); - block->setNode(p, n); - - // If node sources light, add to list - u8 source = nodemgr->get(n).light_source; - if(source != 0) - light_sources.insert(p + posnodes); - - // Collect borders for unlighting - if((x==0 || x == MAP_BLOCKSIZE-1 - || y==0 || y == MAP_BLOCKSIZE-1 - || z==0 || z == MAP_BLOCKSIZE-1) - && oldlight != 0) - { - v3s16 p_map = p + posnodes; - unlight_from[p_map] = oldlight; - } - } - catch(InvalidPositionException &e) - { - /* - This would happen when dealing with a - dummy block. + v3s16 p(x,y,z); + bool is_valid_position; + MapNode n = block->getNode(p, &is_valid_position); + if (!is_valid_position) { + /* This would happen when dealing with a + dummy block. */ - //assert(0); infostream<<"updateLighting(): InvalidPositionException" <setNode(p, n); + + // If node sources light, add to list + u8 source = nodemgr->get(n).light_source; + if(source != 0) + light_sources.insert(p + posnodes); + + // Collect borders for unlighting + if((x==0 || x == MAP_BLOCKSIZE-1 + || y==0 || y == MAP_BLOCKSIZE-1 + || z==0 || z == MAP_BLOCKSIZE-1) + && oldlight != 0) + { + v3s16 p_map = p + posnodes; + unlight_from[p_map] = oldlight; } + + } if(bank == LIGHTBANK_DAY) @@ -921,7 +937,8 @@ void Map::updateLighting(std::map & a_blocks, /* */ void Map::addNodeAndUpdate(v3s16 p, MapNode n, - std::map &modified_blocks) + std::map &modified_blocks, + bool remove_metadata) { INodeDefManager *ndef = m_gamedef->ndef(); @@ -953,15 +970,12 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, Otherwise there probably is. */ - try{ - MapNode topnode = getNode(toppos); - if(topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) - node_under_sunlight = false; - } - catch(InvalidPositionException &e) - { - } + bool is_valid_position; + MapNode topnode = getNodeNoEx(toppos, &is_valid_position); + + if(is_valid_position && topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) + node_under_sunlight = false; /* Remove all light that has come out of this node @@ -976,7 +990,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, { enum LightBank bank = banks[i]; - u8 lightwas = getNode(p).getLight(bank, ndef); + u8 lightwas = getNodeNoEx(p).getLight(bank, ndef); // Add the block of the added node to modified_blocks v3s16 blockpos = getNodeBlockPos(p); @@ -1008,8 +1022,9 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, /* Remove node metadata */ - - removeNodeMetadata(p); + if (remove_metadata) { + removeNodeMetadata(p); + } /* Set the node on the map @@ -1032,13 +1047,10 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, v3s16 n2pos(p.X, y, p.Z); MapNode n2; - try{ - n2 = getNode(n2pos); - } - catch(InvalidPositionException &e) - { + + n2 = getNodeNoEx(n2pos, &is_valid_position); + if (!is_valid_position) break; - } if(n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) { @@ -1099,20 +1111,14 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, }; for(u16 i=0; i<7; i++) { - try - { - v3s16 p2 = p + dirs[i]; - MapNode n2 = getNode(p2); - if(ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR) + MapNode n2 = getNodeNoEx(p2, &is_valid_position); + if(is_valid_position + && (ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)) { m_transforming_liquid.push_back(p2); } - - }catch(InvalidPositionException &e) - { - } } } @@ -1143,15 +1149,11 @@ void Map::removeNodeAndUpdate(v3s16 p, If there is a node at top and it doesn't have sunlight, there will be no sunlight going down. */ - try{ - MapNode topnode = getNode(toppos); + bool is_valid_position; + MapNode topnode = getNodeNoEx(toppos, &is_valid_position); - if(topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) - node_under_sunlight = false; - } - catch(InvalidPositionException &e) - { - } + if(is_valid_position && topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) + node_under_sunlight = false; std::set light_sources; @@ -1168,7 +1170,7 @@ void Map::removeNodeAndUpdate(v3s16 p, Unlight neighbors (in case the node is a light source) */ unLightNeighbors(bank, p, - getNode(p).getLight(bank, ndef), + getNodeNoEx(p).getLight(bank, ndef), light_sources, modified_blocks); } @@ -1228,13 +1230,11 @@ void Map::removeNodeAndUpdate(v3s16 p, { // Set the lighting of this node to 0 // TODO: Is this needed? Lighting is cleared up there already. - try{ - MapNode n = getNode(p); + MapNode n = getNodeNoEx(p, &is_valid_position); + if (is_valid_position) { n.setLight(LIGHTBANK_DAY, 0, ndef); setNode(p, n); - } - catch(InvalidPositionException &e) - { + } else { assert(0); } } @@ -1290,34 +1290,29 @@ void Map::removeNodeAndUpdate(v3s16 p, }; for(u16 i=0; i<7; i++) { - try - { - v3s16 p2 = p + dirs[i]; - MapNode n2 = getNode(p2); - if(ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR) + bool is_position_valid; + MapNode n2 = getNodeNoEx(p2, &is_position_valid); + if (is_position_valid + && (ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)) { m_transforming_liquid.push_back(p2); } - - }catch(InvalidPositionException &e) - { - } } } -bool Map::addNodeWithEvent(v3s16 p, MapNode n) +bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata) { MapEditEvent event; - event.type = MEET_ADDNODE; + event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE; event.p = p; event.n = n; bool succeeded = true; try{ std::map modified_blocks; - addNodeAndUpdate(p, n, modified_blocks); + addNodeAndUpdate(p, n, modified_blocks, remove_metadata); // Copy modified_blocks to event for(std::map::iterator @@ -1460,11 +1455,11 @@ void Map::timerUpdate(float dtime, float unload_timeout, v3s16 p = block->getPos(); // Save if modified - if(block->getModified() != MOD_STATE_CLEAN - && save_before_unloading) + if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) { modprofiler.add(block->getModifiedReason(), 1); - saveBlock(block); + if (!saveBlock(block)) + continue; saved_blocks_count++; } @@ -1604,7 +1599,6 @@ struct NodeNeighbor { NeighborType t; v3s16 p; bool l; //can liquid - bool i; //infinity }; void Map::transforming_liquid_add(v3s16 p) { @@ -1615,23 +1609,7 @@ s32 Map::transforming_liquid_size() { return m_transforming_liquid.size(); } -const v3s16 g_7dirs[7] = -{ - // +right, +top, +back - v3s16( 0,-1, 0), // bottom - v3s16( 0, 0, 0), // self - v3s16( 0, 0, 1), // back - v3s16( 0, 0,-1), // front - v3s16( 1, 0, 0), // right - v3s16(-1, 0, 0), // left - v3s16( 0, 1, 0) // top -}; - -#define D_BOTTOM 0 -#define D_TOP 6 -#define D_SELF 1 - -void Map::transformLiquidsFinite(std::map & modified_blocks) +void Map::transformLiquids(std::map & modified_blocks) { INodeDefManager *nodemgr = m_gamedef->ndef(); @@ -1641,464 +1619,119 @@ void Map::transformLiquidsFinite(std::map & 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"); + /*if(initial_size != 0) + infostream<<"transformLiquids(): initial_size="< must_reflow, must_reflow_second; + UniqueQueue must_reflow; // List of MapBlocks that will require a lighting update (due to lava) std::map lighting_modified_blocks; u16 loop_max = g_settings->getU16("liquid_loop_max"); - while (m_transforming_liquid.size() > 0) + 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) + 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; + + MapNode n0 = getNodeNoEx(p0); + + /* + Collect information about current node + */ + s8 liquid_level = -1; content_t liquid_kind = CONTENT_IGNORE; - content_t liquid_kind_flowing = CONTENT_IGNORE; + LiquidType liquid_type = nodemgr->get(n0).liquid_type; + switch (liquid_type) { + case LIQUID_SOURCE: + liquid_level = LIQUID_LEVEL_SOURCE; + liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing); + break; + case LIQUID_FLOWING: + liquid_level = (n0.param2 & LIQUID_LEVEL_MASK); + liquid_kind = n0.getContent(); + break; + case LIQUID_NONE: + // if this is an air node, it *could* be transformed into a liquid. otherwise, + // continue with the next node. + if (n0.getContent() != CONTENT_AIR) + continue; + liquid_kind = CONTENT_AIR; + break; + } + /* Collect information about the environment */ - const v3s16 *dirs = g_7dirs; - for (u16 i = 0; i < 7; i++) { + const v3s16 *dirs = g_6dirs; + NodeNeighbor sources[6]; // surrounding sources + int num_sources = 0; + NodeNeighbor flows[6]; // surrounding flowing liquid nodes + int num_flows = 0; + NodeNeighbor airs[6]; // surrounding air + int num_airs = 0; + NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid + int num_neutrals = 0; + bool flowing_down = false; + for (u16 i = 0; i < 6; i++) { NeighborType nt = NEIGHBOR_SAME_LEVEL; switch (i) { - case D_TOP: + case 1: nt = NEIGHBOR_UPPER; break; - case D_BOTTOM: + case 4: 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]; - + NodeNeighbor nb = {getNodeNoEx(npos), nt, npos}; switch (nodemgr->get(nb.n.getContent()).liquid_type) { case LIQUID_NONE: if (nb.n.getContent() == CONTENT_AIR) { - liquid_levels[i] = 0; - nb.l = 1; + airs[num_airs++] = nb; + // if the current node is a water source the neighbor + // should be enqueded for transformation regardless of whether the + // current node changes or not. + if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE) + m_transforming_liquid.push_back(npos); + // if the current node happens to be a flowing node, it will start to flow down here. + if (nb.t == NEIGHBOR_LOWER) { + flowing_down = true; + } + } else { + neutrals[num_neutrals++] = nb; } 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); + // if this node is not (yet) of a liquid type, choose the first liquid type we encounter + if (liquid_kind == CONTENT_AIR) + liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing); + if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) { + neutrals[num_neutrals++] = nb; + } else { + // Do not count bottom source, it will screw things up + if(dirs[i].Y != -1) + sources[num_sources++] = nb; } break; case LIQUID_FLOWING: - // if this node is not (yet) of a liquid type, - // choose the first liquid type we encounter - if (liquid_kind_flowing == CONTENT_IGNORE) - liquid_kind_flowing = nb.n.getContent(); - if (liquid_kind == CONTENT_IGNORE) - liquid_kind = nodemgr->getId( - nodemgr->get(nb.n).liquid_alternative_source); - if (nb.n.getContent() == liquid_kind_flowing) { - liquid_levels[i] = (nb.n.param2 & LIQUID_LEVEL_MASK); - nb.l = 1; - } - break; - } - - if (nb.l && nb.t == NEIGHBOR_SAME_LEVEL) - ++can_liquid_same_level; - if (liquid_levels[i] > 0) - total_level += liquid_levels[i]; - - /* - infostream << "get node i=" <<(int)i<<" " << PP(npos) << " c=" - << nb.n.getContent() <<" p0="<< (int)nb.n.param0 <<" p1=" - << (int)nb.n.param1 <<" p2="<< (int)nb.n.param2 << " lt=" - << nodemgr->get(nb.n.getContent()).liquid_type - //<< " lk=" << liquid_kind << " lkf=" << liquid_kind_flowing - << " l="<< nb.l << " inf="<< nb.i << " nlevel=" << (int)liquid_levels[i] - << " tlevel=" << (int)total_level << " cansame=" - << (int)can_liquid_same_level << std::endl; - */ - } - - if (liquid_kind == CONTENT_IGNORE || - !neighbors[D_SELF].l || - total_level <= 0) - continue; - - // fill bottom block - if (neighbors[D_BOTTOM].l) { - liquid_levels_want[D_BOTTOM] = total_level > LIQUID_LEVEL_SOURCE ? - LIQUID_LEVEL_SOURCE : total_level; - total_level -= liquid_levels_want[D_BOTTOM]; - } - - //relax up - if (relax && ((p0.Y == water_level) || (fast_flood && p0.Y <= water_level)) && liquid_levels[D_TOP] == 0 && - liquid_levels[D_BOTTOM] == LIQUID_LEVEL_SOURCE && - total_level >= LIQUID_LEVEL_SOURCE * can_liquid_same_level- - (can_liquid_same_level - relax) && - can_liquid_same_level >= relax + 1) { - total_level = LIQUID_LEVEL_SOURCE * can_liquid_same_level; - } - - // prevent lakes in air above unloaded blocks - if (liquid_levels[D_TOP] == 0 && (p0.Y > water_level || !fast_flood) && neighbors[D_BOTTOM].n.getContent() == CONTENT_IGNORE) { - --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 - && 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 ( 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="<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="< must_reflow; - - // List of MapBlocks that will require a lighting update (due to lava) - std::map 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 >= loop_max) - break; - loopcount++; - - /* - Get a queued transforming liquid node - */ - v3s16 p0 = m_transforming_liquid.pop_front(); - - MapNode n0 = getNodeNoEx(p0); - - /* - Collect information about current node - */ - s8 liquid_level = -1; - content_t liquid_kind = CONTENT_IGNORE; - LiquidType liquid_type = nodemgr->get(n0).liquid_type; - switch (liquid_type) { - case LIQUID_SOURCE: - liquid_level = LIQUID_LEVEL_SOURCE; - liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing); - break; - case LIQUID_FLOWING: - liquid_level = (n0.param2 & LIQUID_LEVEL_MASK); - liquid_kind = n0.getContent(); - break; - case LIQUID_NONE: - // if this is an air node, it *could* be transformed into a liquid. otherwise, - // continue with the next node. - if (n0.getContent() != CONTENT_AIR) - continue; - liquid_kind = CONTENT_AIR; - break; - } - - /* - Collect information about the environment - */ - const v3s16 *dirs = g_6dirs; - NodeNeighbor sources[6]; // surrounding sources - int num_sources = 0; - NodeNeighbor flows[6]; // surrounding flowing liquid nodes - int num_flows = 0; - NodeNeighbor airs[6]; // surrounding air - int num_airs = 0; - NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid - int num_neutrals = 0; - bool flowing_down = false; - for (u16 i = 0; i < 6; i++) { - NeighborType nt = NEIGHBOR_SAME_LEVEL; - switch (i) { - case 1: - nt = NEIGHBOR_UPPER; - break; - case 4: - nt = NEIGHBOR_LOWER; - break; - } - v3s16 npos = p0 + dirs[i]; - NodeNeighbor nb = {getNodeNoEx(npos), nt, npos}; - switch (nodemgr->get(nb.n.getContent()).liquid_type) { - case LIQUID_NONE: - if (nb.n.getContent() == CONTENT_AIR) { - airs[num_airs++] = nb; - // if the current node is a water source the neighbor - // should be enqueded for transformation regardless of whether the - // current node changes or not. - if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE) - m_transforming_liquid.push_back(npos); - // if the current node happens to be a flowing node, it will start to flow down here. - if (nb.t == NEIGHBOR_LOWER) { - flowing_down = true; - } - } else { - neutrals[num_neutrals++] = nb; - } - break; - case LIQUID_SOURCE: - // if this node is not (yet) of a liquid type, choose the first liquid type we encounter - if (liquid_kind == CONTENT_AIR) - liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing); - if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) { - neutrals[num_neutrals++] = nb; - } else { - // Do not count bottom source, it will screw things up - if(dirs[i].Y != -1) - sources[num_sources++] = nb; - } - break; - case LIQUID_FLOWING: - // if this node is not (yet) of a liquid type, choose the first liquid type we encounter - if (liquid_kind == CONTENT_AIR) - liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing); - if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) { - neutrals[num_neutrals++] = nb; - } else { - flows[num_flows++] = nb; - if (nb.t == NEIGHBOR_LOWER) - flowing_down = true; + // if this node is not (yet) of a liquid type, choose the first liquid type we encounter + if (liquid_kind == CONTENT_AIR) + liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing); + if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) { + neutrals[num_neutrals++] = nb; + } else { + flows[num_flows++] = nb; + if (nb.t == NEIGHBOR_LOWER) + flowing_down = true; } break; } @@ -2110,6 +1743,7 @@ void Map::transformLiquids(std::map & modified_blocks) content_t new_node_content; s8 new_node_level = -1; s8 max_node_level = -1; + u8 range = rangelim(nodemgr->get(liquid_kind).liquid_range, 0, LIQUID_LEVEL_MAX+1); if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) { // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid) // or the flowing alternative of the first of the surrounding sources (if it's air), so @@ -2119,6 +1753,8 @@ void Map::transformLiquids(std::map & modified_blocks) // liquid_kind is set properly, see above new_node_content = liquid_kind; max_node_level = new_node_level = LIQUID_LEVEL_MAX; + if (new_node_level < (LIQUID_LEVEL_MAX+1-range)) + new_node_content = CONTENT_AIR; } else { // no surrounding sources, so get the maximum level that can flow into this node for (u16 i = 0; i < num_flows; i++) { @@ -2159,7 +1795,7 @@ void Map::transformLiquids(std::map & modified_blocks) } else new_node_level = max_node_level; - if (new_node_level >= 0) + if (max_node_level >= (LIQUID_LEVEL_MAX+1-range)) new_node_content = liquid_kind; else new_node_content = CONTENT_AIR; @@ -2179,6 +1815,7 @@ void Map::transformLiquids(std::map & 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 @@ -2216,8 +1853,9 @@ void Map::transformLiquids(std::map & modified_blocks) MapBlock *block = getBlockNoCreateNoEx(blockpos); if(block != NULL) { modified_blocks[blockpos] = block; - // If node emits light, MapBlock requires lighting update - if(nodemgr->get(n0).light_source != 0) + // If new or old node emits light, MapBlock requires lighting update + if(nodemgr->get(n0).light_source != 0 || + nodemgr->get(n00).light_source != 0) lighting_modified_blocks[block->getPos()] = block; } @@ -2248,7 +1886,7 @@ void Map::transformLiquids(std::map & modified_blocks) updateLighting(lighting_modified_blocks, modified_blocks); } -NodeMetadata* Map::getNodeMetadata(v3s16 p) +NodeMetadata *Map::getNodeMetadata(v3s16 p) { v3s16 blockpos = getNodeBlockPos(p); v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE; @@ -2258,8 +1896,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p) <m_node_metadata.set(p_rel, meta); + return true; } void Map::removeNodeMetadata(v3s16 p) @@ -2311,8 +1948,7 @@ NodeTimer Map::getNodeTimer(v3s16 p) <getParamsFromSettings(g_settings); - if (!m_mgparams) - m_mgparams = new MapgenV6Params(); - - m_seed = m_mgparams->seed; - - if (g_settings->get("fixed_map_seed").empty()) - { - m_seed = (((u64)(myrand() & 0xffff) << 0) - | ((u64)(myrand() & 0xffff) << 16) - | ((u64)(myrand() & 0xffff) << 32) - | ((u64)(myrand() & 0xffff) << 48)); - m_mgparams->seed = m_seed; - } - /* - Experimental and debug stuff + Try to load map; if not found, create a new one. */ - { + // Determine which database backend to use + std::string conf_path = savedir + DIR_DELIM + "world.mt"; + Settings conf; + bool succeeded = conf.readConfigFile(conf_path.c_str()); + if (!succeeded || !conf.exists("backend")) { + // fall back to sqlite3 + dbase = new Database_SQLite3(this, savedir); + conf.set("backend", "sqlite3"); + } else { + std::string backend = conf.get("backend"); + if (backend == "dummy") + dbase = new Database_Dummy(this); + else if (backend == "sqlite3") + dbase = new Database_SQLite3(this, savedir); + #if USE_LEVELDB + else if (backend == "leveldb") + dbase = new Database_LevelDB(this, savedir); + #endif + #if USE_REDIS + else if (backend == "redis") + dbase = new Database_Redis(this, savedir); + #endif + else + throw BaseException("Unknown map backend"); } - /* - Try to load map; if not found, create a new one. - */ - m_savedir = savedir; m_map_saving_enabled = false; @@ -2429,7 +2064,7 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer infostream<<"ServerMap: Successfully loaded map " <<"metadata from "<params.seed; +} - delete m_mgparams; +s16 ServerMap::getWaterLevel() +{ + return m_emerge->params.water_level; } bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) @@ -2512,7 +2150,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info; EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos)); - s16 chunksize = m_mgparams->chunksize; + s16 chunksize = m_emerge->params.chunksize; s16 coffset = -chunksize / 2; v3s16 chunk_offset(coffset, coffset, coffset); v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize); @@ -2528,7 +2166,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) blockpos_over_limit(blockpos_max + extra_borders)) return false; - data->seed = m_seed; + data->seed = m_emerge->params.seed; data->blockpos_min = blockpos_min; data->blockpos_max = blockpos_max; data->blockpos_requested = blockpos; @@ -2549,6 +2187,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) // Sector metadata is loaded from disk if not already loaded. ServerMapSector *sector = createSector(sectorpos); assert(sector); + (void) sector; for(s16 y=blockpos_min.Y-extra_borders.Y; y<=blockpos_max.Y+extra_borders.Y; y++) @@ -2598,7 +2237,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) //TimeTaker timer("initBlockMake() initialEmerge"); data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max, false); } - + // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE /* for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) { for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) { @@ -2618,7 +2257,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) return true; } -MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, +void ServerMap::finishBlockMake(BlockMakeData *data, std::map &changed_blocks) { v3s16 blockpos_min = data->blockpos_min; @@ -2712,7 +2351,9 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, y<=blockpos_max.Y+extra_borders.Y; y++) { v3s16 p(x, y, z); - getBlockNoCreateNoEx(p)->setLightingExpired(false); + MapBlock * block = getBlockNoCreateNoEx(p); + if (block != NULL) + block->setLightingExpired(false); } #if 0 @@ -2728,7 +2369,8 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, i != changed_blocks.end(); ++i) { MapBlock *block = i->second; - assert(block); + if (!block) + continue; /* Update day/night difference cache of the MapBlocks */ @@ -2749,7 +2391,8 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, { v3s16 p(x, y, z); MapBlock *block = getBlockNoCreateNoEx(p); - assert(block); + if (!block) + continue; block->setGenerated(true); } @@ -2762,6 +2405,8 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, /*infostream<<"finishBlockMake() done for ("< modified_blocks; MapBlock *block = generateBlock(p, modified_blocks); @@ -3077,11 +2721,46 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank) return block; } - }*/ + } +#endif return NULL; } +MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d) +{ + MapBlock *block = getBlockNoCreateNoEx(p3d); + if (block == NULL) + m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false); + + return block; +} + +void ServerMap::prepareBlock(MapBlock *block) { +} + +// N.B. This requires no synchronization, since data will not be modified unless +// the VoxelManipulator being updated belongs to the same thread. +void ServerMap::updateVManip(v3s16 pos) +{ + Mapgen *mg = m_emerge->getCurrentMapgen(); + if (!mg) + return; + + ManualMapVoxelManipulator *vm = mg->vm; + if (!vm) + return; + + if (!vm->m_area.contains(pos)) + return; + + s32 idx = vm->m_area.index(pos); + vm->m_data[idx] = getNodeNoEx(pos); + vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA; + + vm->m_is_dirty = true; +} + s16 ServerMap::findGroundLevel(v2s16 p2d) { #if 0 @@ -3126,81 +2805,12 @@ s16 ServerMap::findGroundLevel(v2s16 p2d) //return (s16)level; } -void ServerMap::createDatabase() { - int e; - assert(m_database); - e = sqlite3_exec(m_database, - "CREATE TABLE IF NOT EXISTS `blocks` (" - "`pos` INT NOT NULL PRIMARY KEY," - "`data` BLOB" - ");" - , NULL, NULL, NULL); - if(e == SQLITE_ABORT) - throw FileNotGoodException("Could not create database structure"); - else - infostream<<"ServerMap: Database structure was created"; -} - -void ServerMap::verifyDatabase() { - if(m_database) - return; - - { - std::string dbp = m_savedir + DIR_DELIM + "map.sqlite"; - bool needs_create = false; - int d; - - /* - Open the database connection - */ - - createDirs(m_savedir); - - if(!fs::PathExists(dbp)) - needs_create = true; - - d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL); - if(d != SQLITE_OK) { - infostream<<"WARNING: Database failed to open: "<Initialized() && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) // ? return true; return false; } -sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) { - return (sqlite3_int64)pos.Z*16777216 + - (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X; -} - void ServerMap::createDirs(std::string path) { if(fs::CreateAllDirs(path) == false) @@ -3230,24 +2840,26 @@ std::string ServerMap::getSectorDir(v2s16 pos, int layout) return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc; default: assert(false); + return ""; } } v2s16 ServerMap::getSectorPos(std::string dirname) { - unsigned int x, y; + unsigned int x = 0, y = 0; int r; - size_t spos = dirname.rfind(DIR_DELIM_C) + 1; - assert(spos != std::string::npos); - if(dirname.size() - spos == 8) + std::string component; + fs::RemoveLastPathComponent(dirname, &component, 1); + if(component.size() == 8) { // Old layout - r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y); + r = sscanf(component.c_str(), "%4x%4x", &x, &y); } - else if(dirname.size() - spos == 3) + else if(component.size() == 3) { // New layout - r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y); + fs::RemoveLastPathComponent(dirname, &component, 2); + r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y); // Sign-extend the 12 bit values up to 16 bits... if(x&0x800) x|=0xF000; if(y&0x800) y|=0xF000; @@ -3372,50 +2984,13 @@ void ServerMap::save(ModifiedState save_level) } } -static s32 unsignedToSigned(s32 i, s32 max_positive) -{ - if(i < max_positive) - return i; - else - return i - 2*max_positive; -} - -// modulo of a negative number does not work consistently in C -static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod) -{ - if(i >= 0) - return i % mod; - return mod - ((-i) % mod); -} - -v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i) -{ - s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048); - i = (i - x) / 4096; - s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048); - i = (i - y) / 4096; - s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048); - return v3s16(x,y,z); -} - void ServerMap::listAllLoadableBlocks(std::list &dst) { if(loadFromFolders()){ errorstream<<"Map::listAllLoadableBlocks(): Result will be missing " <<"all blocks that are stored in flat files"<setParamsToSettings(¶ms); - params.writeLines(os); + m_emerge->saveParamsToSettings(¶ms); + params.writeLines(ss); - os<<"[end_of_params]\n"; + ss<<"[end_of_params]\n"; + + if(!fs::safeWriteToFile(fullpath, ss.str())) + { + infostream<<"ERROR: ServerMap::saveMapMeta(): " + <<"could not write "<getParamsFromSettings(¶ms); - } catch (SettingNotFoundException &e) { - infostream << "Couldn't get a setting from map_meta.txt: " - << e.what() << std::endl; - mgparams = NULL; - } - - if (mgparams) { - if (m_mgparams) - delete m_mgparams; - m_mgparams = mgparams; - m_seed = mgparams->seed; - } else { - if (params.exists("seed")) { - m_seed = params.getU64("seed"); - m_mgparams->seed = m_seed; - } + if (!params.parseConfigLines(is, "[end_of_params]")) { + throw SerializationError("ServerMap::loadMapMeta(): " + "[end_of_params] not found!"); } - verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<loadParamsFromSettings(¶ms); + + verbosestream << "ServerMap::loadMapMeta(): seed=" + << m_emerge->params.seed << std::endl; } void ServerMap::saveSectorMeta(ServerMapSector *sector) { DSTACK(__FUNCTION_NAME); // Format used for writing - u8 version = SER_FMT_VER_HIGHEST; + u8 version = SER_FMT_VER_HIGHEST_WRITE; // Get destination v2s16 pos = sector->getPos(); std::string dir = getSectorDir(pos); createDirs(dir); std::string fullpath = dir + DIR_DELIM + "meta"; - std::ofstream o(fullpath.c_str(), std::ios_base::binary); - if(o.good() == false) - throw FileNotGoodException("Cannot open sector metafile"); + std::ostringstream ss(std::ios_base::binary); + + sector->serialize(ss, version); - sector->serialize(o, version); + if(!fs::safeWriteToFile(fullpath, ss.str())) + throw FileNotGoodException("Cannot write sector metafile"); sector->differs_from_disk = false; } @@ -3698,97 +3245,59 @@ bool ServerMap::loadSectorFull(v2s16 p2d) } #endif -void ServerMap::beginSave() { - verifyDatabase(); - if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK) - infostream<<"WARNING: beginSave() failed, saving might be slow."; +void ServerMap::beginSave() +{ + dbase->beginSave(); } -void ServerMap::endSave() { - verifyDatabase(); - if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK) - infostream<<"WARNING: endSave() failed, map might not have saved."; +void ServerMap::endSave() +{ + dbase->endSave(); } -void ServerMap::saveBlock(MapBlock *block) +bool ServerMap::saveBlock(MapBlock *block) { - DSTACK(__FUNCTION_NAME); - /* - Dummy blocks are not written - */ - if(block->isDummy()) - { - /*v3s16 p = block->getPos(); - infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block " - <<"("<getPos(); + // Dummy blocks are not written + if (block->isDummy()) { + errorstream << "WARNING: saveBlock: Not writing dummy block " + << PP(p3d) << std::endl; + return true; + } -#if 0 - v2s16 p2d(p3d.X, p3d.Z); - std::string sectordir = getSectorDir(p2d); - - createDirs(sectordir); + // Format used for writing + u8 version = SER_FMT_VER_HIGHEST_WRITE; - std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d); - std::ofstream o(fullpath.c_str(), std::ios_base::binary); - if(o.good() == false) - throw FileNotGoodException("Cannot open block data"); -#endif /* [0] u8 serialization version [1] data */ - - verifyDatabase(); - std::ostringstream o(std::ios_base::binary); - - o.write((char*)&version, 1); - - // Write basic data + o.write((char*) &version, 1); block->serialize(o, version, true); - // Write block to database - - std::string tmp = o.str(); - const char *bytes = tmp.c_str(); - - bool success = true; - if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) { - infostream<<"WARNING: Block position failed to bind: "<saveBlock(p3d, data); + if(ret) { + // We just wrote it to the disk so clear modified flag block->resetModified(); + } + return ret; } -void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load) +void ServerMap::loadBlock(std::string sectordir, std::string blockfile, + MapSector *sector, bool save_after_load) { DSTACK(__FUNCTION_NAME); std::string fullpath = sectordir+DIR_DELIM+blockfile; - try{ + try { std::ifstream is(fullpath.c_str(), std::ios_base::binary); if(is.good() == false) @@ -3833,7 +3342,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); @@ -3852,7 +3361,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto <<" (SerializationError). " <<"what()="<loadBlock(blockpos); + if (ret != "") { + loadBlock(&ret, blockpos, createSector(p2d), false); + return getBlockNoCreateNoEx(blockpos); } + // Not found in database, try the files // The directory layout we're going to load from. // 1 - original sectors/xxxxzzzz/ @@ -4028,167 +3513,11 @@ void ServerMap::PrintInfo(std::ostream &out) out<<"ServerMap: "; } -/* - MapVoxelManipulator -*/ - -MapVoxelManipulator::MapVoxelManipulator(Map *map) -{ - m_map = map; -} - -MapVoxelManipulator::~MapVoxelManipulator() -{ - /*infostream<<"MapVoxelManipulator: blocks: "<::iterator n; - n = m_loaded_blocks.find(p); - if(n != m_loaded_blocks.end()) - continue; - - bool block_data_inexistent = false; - try - { - TimeTaker timer1("emerge load", &emerge_load_time); - - /*infostream<<"Loading block (caller_id="<getBlockNoCreate(p); - if(block->isDummy()) - block_data_inexistent = true; - else - block->copyTo(*this); - } - catch(InvalidPositionException &e) - { - block_data_inexistent = true; - } - - if(block_data_inexistent) - { - flags |= VMANIP_BLOCK_DATA_INEXIST; - - VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1)); - // Fill with VOXELFLAG_INEXISTENT - for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++) - for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++) - { - s32 i = m_area.index(a.MinEdge.X,y,z); - memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE); - } - } - /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE) - { - // Mark that block was loaded as blank - flags |= VMANIP_BLOCK_CONTAINS_CIGNORE; - }*/ - - m_loaded_blocks[p] = flags; - } - - //infostream<<"emerge done"< & modified_blocks) -{ - if(m_area.getExtent() == v3s16(0,0,0)) - return; - - //TimeTaker timer1("blitBack"); - - /*infostream<<"blitBack(): m_loaded_blocks.size()=" - <getBlockNoCreate(blockpos); - blockpos_last = blockpos; - block_checked_in_modified = false; - } - - // Calculate relative position in block - v3s16 relpos = p - blockpos * MAP_BLOCKSIZE; - - // Don't continue if nothing has changed here - if(block->getNode(relpos) == n) - continue; - - //m_map->setNode(m_area.MinEdge + p, n); - block->setNode(relpos, n); - - /* - Make sure block is in modified_blocks - */ - if(block_checked_in_modified == false) - { - modified_blocks[blockpos] = block; - block_checked_in_modified = true; - } - } - catch(InvalidPositionException &e) - { - } - } -} - ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map): - MapVoxelManipulator(map), - m_create_area(false) + VoxelManipulator(), + m_is_dirty(false), + m_create_area(false), + m_map(map) { } @@ -4196,12 +3525,6 @@ ManualMapVoxelManipulator::~ManualMapVoxelManipulator() { } -void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id) -{ - // Just create the area so that it can be pointed to - VoxelManipulator::emerge(a, caller_id); -} - void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, bool load_if_inexistent) { @@ -4255,7 +3578,7 @@ void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min, if(block_data_inexistent) { - + if (load_if_inexistent) { ServerMap *svrmap = (ServerMap *)m_map; block = svrmap->emergeBlock(p, false); @@ -4265,17 +3588,17 @@ void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min, block->copyTo(*this); } else { flags |= VMANIP_BLOCK_DATA_INEXIST; - + /* Mark area inexistent */ VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1)); - // Fill with VOXELFLAG_INEXISTENT + // Fill with VOXELFLAG_NO_DATA for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++) for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++) { s32 i = m_area.index(a.MinEdge.X,y,z); - memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE); + memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE); } } } @@ -4287,10 +3610,13 @@ void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min, m_loaded_blocks[p] = flags; } + + m_is_dirty = false; } void ManualMapVoxelManipulator::blitBackAll( - std::map * modified_blocks) + std::map *modified_blocks, + bool overwrite_generated) { if(m_area.getExtent() == v3s16(0,0,0)) return; @@ -4305,10 +3631,9 @@ void ManualMapVoxelManipulator::blitBackAll( v3s16 p = i->first; MapBlock *block = m_map->getBlockNoCreateNoEx(p); bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST); - if(existed == false) - { + if ((existed == false) || (block == NULL) || + (overwrite_generated == false && block->isGenerated() == true)) continue; - } block->copyFrom(*this);