X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmap.cpp;h=236972ae98a08751889f437e567e60709a2466f6;hb=b2102bfe49002f1ac10ca8288f5337e9feec7f65;hp=f128aff6c99d863f57069cf06d97ec4daa67d906;hpb=92833a07d111c55f61b23f66fd8aaa95f3239c33;p=minetest.git diff --git a/src/map.cpp b/src/map.cpp index f128aff6c..236972ae9 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 "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() @@ -921,7 +932,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(); @@ -1008,8 +1020,9 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, /* Remove node metadata */ - - removeNodeMetadata(p); + if (remove_metadata) { + removeNodeMetadata(p); + } /* Set the node on the map @@ -1307,17 +1320,17 @@ void Map::removeNodeAndUpdate(v3s16 p, } } -bool Map::addNodeWithEvent(v3s16 p, MapNode n) +bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata) { MapEditEvent event; - event.type = MEET_ADDNODE; + event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE; event.p = p; event.n = n; bool succeeded = true; try{ 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 +1473,11 @@ void Map::timerUpdate(float dtime, float unload_timeout, v3s16 p = block->getPos(); // Save if modified - if(block->getModified() != MOD_STATE_CLEAN - && save_before_unloading) + if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) { modprofiler.add(block->getModifiedReason(), 1); - saveBlock(block); + if (!saveBlock(block)) + continue; saved_blocks_count++; } @@ -1604,7 +1617,6 @@ struct NodeNeighbor { NeighborType t; v3s16 p; bool l; //can liquid - bool i; //infinity }; void Map::transforming_liquid_add(v3s16 p) { @@ -1615,376 +1627,8 @@ s32 Map::transforming_liquid_size() { return m_transforming_liquid.size(); } -const v3s16 g_7dirs[7] = -{ - // +right, +top, +back - v3s16( 0,-1, 0), // bottom - v3s16( 0, 0, 0), // self - v3s16( 0, 0, 1), // back - v3s16( 0, 0,-1), // front - v3s16( 1, 0, 0), // right - v3s16(-1, 0, 0), // left - v3s16( 0, 1, 0) // top -}; - -#define D_BOTTOM 0 -#define D_TOP 6 -#define D_SELF 1 - -void Map::transformLiquidsFinite(std::map & 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"); - - // list of nodes that due to viscosity have not reached their max level height - UniqueQueue must_reflow, must_reflow_second; - - // 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"); - - //if (m_transforming_liquid.size() > 0) errorstream << "Liquid queue 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] = 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]; - } - - //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="<ndef(); DSTACK(__FUNCTION_NAME); @@ -2117,6 +1761,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 @@ -2126,6 +1771,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++) { @@ -2166,7 +1813,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; @@ -2186,6 +1833,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 @@ -2223,8 +1871,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; } @@ -2255,7 +1904,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; @@ -2265,8 +1914,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p) <m_node_metadata.set(p_rel, meta); + return true; } void Map::removeNodeMetadata(v3s16 p) @@ -2318,8 +1966,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; @@ -2436,7 +2082,7 @@ ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emer infostream<<"ServerMap: Successfully loaded map " <<"metadata from "<params.seed; +} + +s16 ServerMap::getWaterLevel() +{ + return m_emerge->params.water_level; } bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) @@ -2519,7 +2168,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); @@ -2535,7 +2184,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) blockpos_over_limit(blockpos_max + extra_borders)) return false; - data->seed = m_seed; + data->seed = m_emerge->params.seed; data->blockpos_min = blockpos_min; data->blockpos_max = blockpos_max; data->blockpos_requested = blockpos; @@ -2556,6 +2205,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos) // Sector metadata is loaded from disk if not already loaded. ServerMapSector *sector = createSector(sectorpos); assert(sector); + (void) sector; for(s16 y=blockpos_min.Y-extra_borders.Y; y<=blockpos_max.Y+extra_borders.Y; y++) @@ -2605,7 +2255,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++) { @@ -2625,7 +2275,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; @@ -2719,7 +2369,9 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, y<=blockpos_max.Y+extra_borders.Y; y++) { v3s16 p(x, y, z); - getBlockNoCreateNoEx(p)->setLightingExpired(false); + MapBlock * block = getBlockNoCreateNoEx(p); + if (block != NULL) + block->setLightingExpired(false); } #if 0 @@ -2735,7 +2387,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 */ @@ -2756,7 +2409,8 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, { v3s16 p(x, y, z); MapBlock *block = getBlockNoCreateNoEx(p); - assert(block); + if (!block) + continue; block->setGenerated(true); } @@ -2769,6 +2423,8 @@ MapBlock* ServerMap::finishBlockMake(BlockMakeData *data, /*infostream<<"finishBlockMake() done for ("< modified_blocks; MapBlock *block = generateBlock(p, modified_blocks); @@ -3084,11 +2739,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 @@ -3133,81 +2823,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) @@ -3237,12 +2858,13 @@ 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; std::string component; fs::RemoveLastPathComponent(dirname, &component, 1); @@ -3380,50 +3002,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; - } - } - verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<loadParamsFromSettings(¶ms); + + verbosestream<<"ServerMap::loadMapMeta(): seed=" + << m_emerge->params.seed<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; } @@ -3706,97 +3275,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) @@ -3841,7 +3372,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); @@ -3860,7 +3391,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/ @@ -4036,167 +3543,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) { } @@ -4204,12 +3555,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) { @@ -4263,7 +3608,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); @@ -4273,17 +3618,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); } } } @@ -4295,10 +3640,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; @@ -4313,10 +3661,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);