X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmap.cpp;h=32675f08d96523c5b2f640a2912ffcb0279a79ca;hb=8b875d71d1ab928e9866914b886ff58cf8a38192;hp=e47b1b212c44de752af391e60da26ed25a9c46ec;hpb=84b85964fac715d03fef7094d2cdcd5945cb0dd2;p=oweals%2Fminetest.git diff --git a/src/map.cpp b/src/map.cpp index e47b1b212..32675f08d 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -29,12 +29,21 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen.h" #include "nodemetadata.h" -extern "C" { - #include "sqlite3.h" -} /* SQLite format specification: - Initially only replaces sectors/ and sectors2/ + + If map.sqlite does not exist in the save dir + or the block was not found in the database + the map will try to load from sectors folder. + In either case, map.sqlite will be created + and all future saves will save there. + + Structure of map.sqlite: + Tables: + blocks + (PK) INT pos + BLOB data */ /* @@ -630,9 +639,9 @@ s16 Map::propagateSunlight(v3s16 start, else { /*// Turn mud into grass - if(n.d == CONTENT_MUD) + if(n.getContent() == CONTENT_MUD) { - n.d = CONTENT_GRASS; + n.setContent(CONTENT_GRASS); block->setNode(relpos, n); modified_blocks.insert(blockpos, block); }*/ @@ -881,7 +890,7 @@ void Map::updateLighting(core::map & a_blocks, /* */ void Map::addNodeAndUpdate(v3s16 p, MapNode n, - core::map &modified_blocks) + core::map &modified_blocks, std::string &player_name) { /*PrintInfo(m_dout); m_dout<clone(); + meta->setOwner(player_name); setNodeMetadata(p, meta); } @@ -1015,7 +1025,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, TODO: This could be optimized by mass-unlighting instead of looping */ - if(node_under_sunlight && !content_features(n.d).sunlight_propagates) + if(node_under_sunlight && !content_features(n).sunlight_propagates) { s16 y = p.Y - 1; for(;; y--){ @@ -1086,7 +1096,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, v3s16 p2 = p + dirs[i]; MapNode n2 = getNode(p2); - if(content_liquid(n2.d) || n2.d == CONTENT_AIR) + if(content_liquid(n2.getContent()) || n2.getContent() == CONTENT_AIR) { m_transforming_liquid.push_back(p2); } @@ -1111,7 +1121,7 @@ void Map::removeNodeAndUpdate(v3s16 p, v3s16 toppos = p + v3s16(0,1,0); // Node will be replaced with this - u8 replace_material = CONTENT_AIR; + content_t replace_material = CONTENT_AIR; /* If there is a node at top and it doesn't have sunlight, @@ -1158,7 +1168,7 @@ void Map::removeNodeAndUpdate(v3s16 p, */ MapNode n; - n.d = replace_material; + n.setContent(replace_material); setNode(p, n); for(s32 i=0; i<2; i++) @@ -1260,7 +1270,7 @@ void Map::removeNodeAndUpdate(v3s16 p, v3s16 p2 = p + dirs[i]; MapNode n2 = getNode(p2); - if(content_liquid(n2.d) || n2.d == CONTENT_AIR) + if(content_liquid(n2.getContent()) || n2.getContent() == CONTENT_AIR) { m_transforming_liquid.push_back(p2); } @@ -1281,7 +1291,8 @@ bool Map::addNodeWithEvent(v3s16 p, MapNode n) bool succeeded = true; try{ core::map modified_blocks; - addNodeAndUpdate(p, n, modified_blocks); + std::string st = std::string(""); + addNodeAndUpdate(p, n, modified_blocks, st); // Copy modified_blocks to event for(core::map::Iterator @@ -1399,6 +1410,7 @@ void Map::timerUpdate(float dtime, float unload_timeout, core::map::Iterator si; + beginSave(); si = m_sectors.getIterator(); for(; si.atEnd() == false; si++) { @@ -1408,6 +1420,7 @@ void Map::timerUpdate(float dtime, float unload_timeout, core::list blocks; sector->getBlocks(blocks); + for(core::list::Iterator i = blocks.begin(); i != blocks.end(); i++) { @@ -1446,6 +1459,7 @@ void Map::timerUpdate(float dtime, float unload_timeout, sector_deletion_queue.push_back(si.getNode()->getKey()); } } + endSave(); // Finally delete the empty sectors deleteSectors(sector_deletion_queue); @@ -1562,50 +1576,54 @@ void Map::transformLiquids(core::map & modified_blocks) /*if(initial_size != 0) dstream<<"transformLiquids(): initial_size="< must_reflow; + + // List of MapBlocks that will require a lighting update (due to lava) + core::map 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 * 3) + 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; u8 liquid_kind = CONTENT_IGNORE; - LiquidType liquid_type = content_features(n0.d).liquid_type; + LiquidType liquid_type = content_features(n0.getContent()).liquid_type; switch (liquid_type) { case LIQUID_SOURCE: - liquid_level = 8; - liquid_kind = content_features(n0.d).liquid_alternative_flowing; + liquid_level = LIQUID_LEVEL_SOURCE; + liquid_kind = content_features(n0.getContent()).liquid_alternative_flowing; break; case LIQUID_FLOWING: liquid_level = (n0.param2 & LIQUID_LEVEL_MASK); - liquid_kind = n0.d; + 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.d != CONTENT_AIR) + if (n0.getContent() != CONTENT_AIR) continue; liquid_kind = CONTENT_AIR; break; } - + /* Collect information about the environment */ - v3s16 dirs[6] = { - v3s16( 0, 1, 0), // top - v3s16( 0,-1, 0), // bottom - v3s16( 1, 0, 0), // right - v3s16(-1, 0, 0), // left - v3s16( 0, 0, 1), // back - v3s16( 0, 0,-1), // front - }; + const v3s16 *dirs = g_6dirs; NodeNeighbor sources[6]; // surrounding sources int num_sources = 0; NodeNeighbor flows[6]; // surrounding flowing liquid nodes @@ -1618,22 +1636,28 @@ void Map::transformLiquids(core::map & modified_blocks) for (u16 i = 0; i < 6; i++) { NeighborType nt = NEIGHBOR_SAME_LEVEL; switch (i) { - case 0: + case 1: nt = NEIGHBOR_UPPER; break; - case 1: + case 4: nt = NEIGHBOR_LOWER; break; } v3s16 npos = p0 + dirs[i]; NodeNeighbor nb = {getNodeNoEx(npos), nt, npos}; - switch (content_features(nb.n.d).liquid_type) { + switch (content_features(nb.n.getContent()).liquid_type) { case LIQUID_NONE: - if (nb.n.d == CONTENT_AIR) { + 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) + if (nb.t == NEIGHBOR_LOWER) { flowing_down = true; + } } else { neutrals[num_neutrals++] = nb; } @@ -1641,8 +1665,8 @@ void Map::transformLiquids(core::map & modified_blocks) 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 = content_features(nb.n.d).liquid_alternative_flowing; - if (content_features(nb.n.d).liquid_alternative_flowing !=liquid_kind) { + liquid_kind = content_features(nb.n.getContent()).liquid_alternative_flowing; + if (content_features(nb.n.getContent()).liquid_alternative_flowing !=liquid_kind) { neutrals[num_neutrals++] = nb; } else { sources[num_sources++] = nb; @@ -1651,8 +1675,8 @@ void Map::transformLiquids(core::map & modified_blocks) 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 = content_features(nb.n.d).liquid_alternative_flowing; - if (content_features(nb.n.d).liquid_alternative_flowing != liquid_kind) { + liquid_kind = content_features(nb.n.getContent()).liquid_alternative_flowing; + if (content_features(nb.n.getContent()).liquid_alternative_flowing != liquid_kind) { neutrals[num_neutrals++] = nb; } else { flows[num_flows++] = nb; @@ -1662,12 +1686,13 @@ void Map::transformLiquids(core::map & modified_blocks) break; } } - + /* decide on the type (and possibly level) of the current node */ - u8 new_node_content; + content_t new_node_content; s8 new_node_level = -1; + s8 max_node_level = -1; if (num_sources >= 2 || 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 @@ -1676,81 +1701,92 @@ void Map::transformLiquids(core::map & modified_blocks) } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) { // liquid_kind is set properly, see above new_node_content = liquid_kind; - new_node_level = 7; + max_node_level = new_node_level = LIQUID_LEVEL_MAX; } else { // no surrounding sources, so get the maximum level that can flow into this node for (u16 i = 0; i < num_flows; i++) { u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK); switch (flows[i].t) { case NEIGHBOR_UPPER: - if (nb_liquid_level + WATER_DROP_BOOST > new_node_level) { - new_node_level = 7; - if (nb_liquid_level + WATER_DROP_BOOST < 7) - new_node_level = nb_liquid_level + WATER_DROP_BOOST; - } + if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) { + max_node_level = LIQUID_LEVEL_MAX; + if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX) + max_node_level = nb_liquid_level + WATER_DROP_BOOST; + } else if (nb_liquid_level > max_node_level) + max_node_level = nb_liquid_level; break; case NEIGHBOR_LOWER: break; case NEIGHBOR_SAME_LEVEL: if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK && - nb_liquid_level > 0 && nb_liquid_level - 1 > new_node_level) { - new_node_level = nb_liquid_level - 1; + nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) { + max_node_level = nb_liquid_level - 1; } break; } } - // don't flow as far in open terrain - if there isn't at least one adjacent solid block, - // substract another unit from the resulting water level. - if (!flowing_down && new_node_level >= 1) { - bool at_wall = false; - for (u16 i = 0; i < num_neutrals; i++) { - if (neutrals[i].t == NEIGHBOR_SAME_LEVEL) { - at_wall = true; - break; - } - } - if (!at_wall) - new_node_level -= 1; - } - + + u8 viscosity = content_features(liquid_kind).liquid_viscosity; + if (viscosity > 1 && max_node_level != liquid_level) { + // amount to gain, limited by viscosity + // must be at least 1 in absolute value + s8 level_inc = max_node_level - liquid_level; + if (level_inc < -viscosity || level_inc > viscosity) + new_node_level = liquid_level + level_inc/viscosity; + else if (level_inc < 0) + new_node_level = liquid_level - 1; + else if (level_inc > 0) + new_node_level = liquid_level + 1; + if (new_node_level != max_node_level) + must_reflow.push_back(p0); + } else + new_node_level = max_node_level; + if (new_node_level >= 0) new_node_content = liquid_kind; else new_node_content = CONTENT_AIR; + } - + /* check if anything has changed. if not, just continue with the next node. */ - if (new_node_content == n0.d && (content_features(n0.d).liquid_type != LIQUID_FLOWING || + if (new_node_content == n0.getContent() && (content_features(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))) continue; - - + + /* update the current node */ bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK)); - n0.d = new_node_content; - if (content_features(n0.d).liquid_type == LIQUID_FLOWING) { + if (content_features(new_node_content).liquid_type == LIQUID_FLOWING) { // set level to last 3 bits, flowing down bit to 4th bit n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK); } else { - n0.param2 = 0; + // set the liquid level and flow bit to 0 + n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK); } + n0.setContent(new_node_content); setNode(p0, n0); v3s16 blockpos = getNodeBlockPos(p0); MapBlock *block = getBlockNoCreateNoEx(blockpos); - if(block != NULL) + if(block != NULL) { modified_blocks.insert(blockpos, block); - + // If node emits light, MapBlock requires lighting update + if(content_features(n0).light_source != 0) + lighting_modified_blocks[block->getPos()] = block; + } + /* enqueue neighbors for update if neccessary */ - switch (content_features(n0.d).liquid_type) { + switch (content_features(n0.getContent()).liquid_type) { case LIQUID_SOURCE: + case LIQUID_FLOWING: // make sure source flows into all neighboring nodes for (u16 i = 0; i < num_flows; i++) if (flows[i].t != NEIGHBOR_UPPER) @@ -1764,28 +1800,12 @@ void Map::transformLiquids(core::map & modified_blocks) for (u16 i = 0; i < num_flows; i++) m_transforming_liquid.push_back(flows[i].p); break; - case LIQUID_FLOWING: - for (u16 i = 0; i < num_flows; i++) { - u8 flow_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK); - // liquid_level is still the ORIGINAL level of this node. - if (flows[i].t != NEIGHBOR_UPPER && ((flow_level < liquid_level || flow_level < new_node_level) || - flow_down_enabled)) - m_transforming_liquid.push_back(flows[i].p); - } - for (u16 i = 0; i < num_airs; i++) { - if (airs[i].t != NEIGHBOR_UPPER && (airs[i].t == NEIGHBOR_LOWER || new_node_level > 0)) - m_transforming_liquid.push_back(airs[i].p); - } - break; - } - - loopcount++; - //if(loopcount >= 100000) - if(loopcount >= initial_size * 10) { - break; } } //dstream<<"Map::transformLiquids(): loopcount="< 0) + m_transforming_liquid.push_back(must_reflow.pop_front()); + updateLighting(lighting_modified_blocks, modified_blocks); } NodeMetadata* Map::getNodeMetadata(v3s16 p) @@ -1867,16 +1887,26 @@ void Map::nodeMetadataStep(float dtime, ServerMap::ServerMap(std::string savedir): Map(dout_server), m_seed(0), - m_map_metadata_changed(true) + m_map_metadata_changed(true), + m_database(NULL), + m_database_read(NULL), + m_database_write(NULL) { dstream<<__FUNCTION_NAME<no_op = true; + return; + } + data->no_op = false; data->seed = m_seed; data->blockpos = blockpos; @@ -2026,25 +2076,28 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos) for(s16 y=-1; y<=1; y++) { - //MapBlock *block = createBlock(blockpos); + v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z); + //MapBlock *block = createBlock(p); // 1) get from memory, 2) load from disk - MapBlock *block = emergeBlock(blockpos, false); + MapBlock *block = emergeBlock(p, false); // 3) create a blank one if(block == NULL) - block = createBlock(blockpos); + { + block = createBlock(p); + + /* + Block gets sunlight if this is true. + + Refer to the map generator heuristics. + */ + bool ug = mapgen::block_is_underground(data->seed, p); + block->setIsUnderground(ug); + } // Lighting will not be valid after make_chunk is called block->setLightingExpired(true); // Lighting will be calculated //block->setLightingExpired(false); - - /* - Block gets sunlight if this is true. - - This should be set to true when the top side of a block - is completely exposed to the sky. - */ - block->setIsUnderground(false); } } } @@ -2056,6 +2109,7 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos) neighboring blocks */ + // The area that contains this block and it's neighbors v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1); v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1); @@ -2080,7 +2134,7 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data, if(data->no_op) { - dstream<<"finishBlockMake(): no-op"<setIsUnderground(mapgen::block_is_underground(data->seed, blockpos)); - block->setIsUnderground(mapgen::block_is_underground(data->seed, blockpos)); /* Add sunlight to central block. @@ -2153,6 +2211,13 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data, #if 1 // Center block lighting_update_blocks.insert(block->getPos(), block); + + /*{ + s16 x = 0; + s16 z = 0; + v3s16 p = block->getPos()+v3s16(x,1,z); + lighting_update_blocks[p] = getBlockNoCreateNoEx(p); + }*/ #endif #if 0 // All modified blocks @@ -2169,8 +2234,28 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data, lighting_update_blocks.insert(i.getNode()->getKey(), i.getNode()->getValue()); } + /*// Also force-add all the upmost blocks for proper sunlight + for(s16 x=-1; x<=1; x++) + for(s16 z=-1; z<=1; z++) + { + v3s16 p = block->getPos()+v3s16(x,1,z); + lighting_update_blocks[p] = getBlockNoCreateNoEx(p); + }*/ #endif updateLighting(lighting_update_blocks, changed_blocks); + + /* + Set lighting to non-expired state in all of them. + This is cheating, but it is not fast enough if all of them + would actually be updated. + */ + for(s16 x=-1; x<=1; x++) + for(s16 y=-1; y<=1; y++) + for(s16 z=-1; z<=1; z++) + { + v3s16 p = block->getPos()+v3s16(x,y,z); + getBlockNoCreateNoEx(p)->setLightingExpired(false); + } if(enable_mapgen_debug_info == false) t.stop(true); // Hide output @@ -2212,7 +2297,26 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data, /*dstream<<"finishBlockMake() done for ("<getPos()+v3s16(x,y,z); + MapBlock *block = getBlockNoCreateNoEx(p); + char spos[20]; + snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z); + dstream<<"Generated "<getNode(p); - if(n.d == CONTENT_IGNORE) + bool erroneus_content = false; + for(s16 z0=0; z0getNode(p); + if(n.getContent() == CONTENT_IGNORE) + { + dstream<<"CONTENT_IGNORE at " + <<"("<setNode(v3s16(x0,y0,z0), n); + for(s16 y0=0; y0setNode(v3s16(x0,y0,z0), n); + } } } #endif @@ -2456,7 +2566,7 @@ MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate) { MapBlock *block = getBlockNoCreateNoEx(p); - if(block) + if(block && block->isDummy() == false) return block; } @@ -2653,19 +2763,19 @@ s16 ServerMap::findGroundLevel(v2s16 p2d) for(; p.Y>min; p.Y--) { MapNode n = getNodeNoEx(p); - if(n.d != CONTENT_IGNORE) + if(n.getContent() != CONTENT_IGNORE) break; } if(p.Y == min) goto plan_b; // If this node is not air, go to plan b - if(getNodeNoEx(p).d != CONTENT_AIR) + if(getNodeNoEx(p).getContent() != CONTENT_AIR) goto plan_b; // Search existing walkable and return it for(; p.Y>min; p.Y--) { MapNode n = getNodeNoEx(p); - if(content_walkable(n.d) && n.d != CONTENT_IGNORE) + if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE) return p.Y; } @@ -2684,6 +2794,75 @@ plan_b: //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 + dstream<<"Server: Database structure was created"; +} + +void ServerMap::verifyDatabase() { + if(m_database) + return; + + { + std::string dbp = m_savedir + "/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) { + dstream<<"WARNING: Database failed to open: "<::Iterator i = m_sectors.getIterator(); for(; i.atEnd() == false; i++) { @@ -2801,6 +2981,8 @@ void ServerMap::save(bool only_changed) core::list blocks; sector->getBlocks(blocks); core::list::Iterator j; + + //sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL); for(j=blocks.begin(); j!=blocks.end(); j++) { MapBlock *block = *j; @@ -2819,8 +3001,10 @@ void ServerMap::save(bool only_changed) <getPos().Z<<")" <getPos(); + +#if 0 v2s16 p2d(p3d.X, p3d.Z); std::string sectordir = getSectorDir(p2d); @@ -3107,11 +3305,16 @@ void ServerMap::saveBlock(MapBlock *block) 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 @@ -3119,7 +3322,23 @@ void ServerMap::saveBlock(MapBlock *block) // Write extra data stored on disk block->serializeDiskExtra(o, version); - + + // Write block to database + + std::string tmp = o.str(); + const char *bytes = tmp.c_str(); + + if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) + dstream<<"WARNING: Block position failed to bind: "<resetModified(); } @@ -3180,6 +3399,9 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto if(version < SER_FMT_VER_HIGHEST || save_after_load) { saveBlock(block); + + // Should be in database now, so delete the old file + fs::RecursiveDelete(fullpath); } // We just loaded it from the disk, so it's up-to-date. @@ -3200,12 +3422,111 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto } } +void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load) +{ + DSTACK(__FUNCTION_NAME); + + try { + std::istringstream is(*blob, std::ios_base::binary); + + u8 version = SER_FMT_VER_INVALID; + is.read((char*)&version, 1); + + if(is.fail()) + throw SerializationError("ServerMap::loadBlock(): Failed" + " to read MapBlock version"); + + /*u32 block_size = MapBlock::serializedLength(version); + SharedBuffer data(block_size); + is.read((char*)*data, block_size);*/ + + // This will always return a sector because we're the server + //MapSector *sector = emergeSector(p2d); + + MapBlock *block = NULL; + bool created_new = false; + block = sector->getBlockNoCreateNoEx(p3d.Y); + if(block == NULL) + { + block = sector->createBlankBlockNoInsert(p3d.Y); + created_new = true; + } + + // Read basic data + block->deSerialize(is, version); + + // Read extra data stored on disk + block->deSerializeDiskExtra(is, version); + + // If it's a new block, insert it to the map + if(created_new) + sector->insertBlock(block); + + /* + Save blocks loaded in old format in new format + */ + + if(version < SER_FMT_VER_HIGHEST || save_after_load) + { + saveBlock(block); + } + + // We just loaded it from, so it's up-to-date. + block->resetModified(); + + } + catch(SerializationError &e) + { + dstream<<"WARNING: Invalid block data in database " + <<" (SerializationError). " + <<"what()="<getKey(); bool existed = i.getNode()->getValue(); if(existed == false) + { + // The Great Bug was found using this + /*dstream<<"ManualMapVoxelManipulator::blitBackAll: " + <<"Inexistent ("<getKey(); + } MapBlock *block = m_map->getBlockNoCreateNoEx(p); if(block == NULL) {