diff options
Diffstat (limited to 'src/mapblock.cpp')
-rw-r--r-- | src/mapblock.cpp | 166 |
1 files changed, 113 insertions, 53 deletions
diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 0ca71e643..4958d3a65 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -355,7 +355,7 @@ static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes, } } -void MapBlock::serialize(std::ostream &os, u8 version, bool disk, int compression_level) +void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int compression_level) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); @@ -365,6 +365,9 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk, int compressio FATAL_ERROR_IF(version < SER_FMT_VER_LOWEST_WRITE, "Serialisation version error"); + std::ostringstream os_raw(std::ios_base::binary); + std::ostream &os = version >= 29 ? os_raw : os_compressed; + // First byte u8 flags = 0; if(is_underground) @@ -382,37 +385,52 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk, int compressio Bulk node data */ NameIdMapping nimap; - if(disk) + SharedBuffer<u8> buf; + const u8 content_width = 2; + const u8 params_width = 2; + if(disk) { MapNode *tmp_nodes = new MapNode[nodecount]; - for(u32 i=0; i<nodecount; i++) - tmp_nodes[i] = data[i]; + memcpy(tmp_nodes, data, nodecount * sizeof(MapNode)); getBlockNodeIdMapping(&nimap, tmp_nodes, m_gamedef->ndef()); - u8 content_width = 2; - u8 params_width = 2; - writeU8(os, content_width); - writeU8(os, params_width); - MapNode::serializeBulk(os, version, tmp_nodes, nodecount, - content_width, params_width, compression_level); + buf = MapNode::serializeBulk(version, tmp_nodes, nodecount, + content_width, params_width); delete[] tmp_nodes; + + // write timestamp and node/id mapping first + if (version >= 29) { + writeU32(os, getTimestamp()); + + nimap.serialize(os); + } } else { - u8 content_width = 2; - u8 params_width = 2; - writeU8(os, content_width); - writeU8(os, params_width); - MapNode::serializeBulk(os, version, data, nodecount, - content_width, params_width, compression_level); + buf = MapNode::serializeBulk(version, data, nodecount, + content_width, params_width); + } + + writeU8(os, content_width); + writeU8(os, params_width); + if (version >= 29) { + os.write(reinterpret_cast<char*>(*buf), buf.getSize()); + } else { + // prior to 29 node data was compressed individually + compress(buf, os, version, compression_level); } /* Node metadata */ - std::ostringstream oss(std::ios_base::binary); - m_node_metadata.serialize(oss, version, disk); - compressZlib(oss.str(), os, compression_level); + if (version >= 29) { + m_node_metadata.serialize(os, version, disk); + } else { + // use os_raw from above to avoid allocating another stream object + m_node_metadata.serialize(os_raw, version, disk); + // prior to 29 node data was compressed individually + compress(os_raw.str(), os, version, compression_level); + } /* Data that goes to disk, but not the network @@ -427,17 +445,24 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk, int compressio // Static objects m_static_objects.serialize(os); - // Timestamp - writeU32(os, getTimestamp()); + if(version < 29){ + // Timestamp + writeU32(os, getTimestamp()); - // Write block-specific node definition id mapping - nimap.serialize(os); + // Write block-specific node definition id mapping + nimap.serialize(os); + } if(version >= 25){ // Node timers m_node_timers.serialize(os, version); } } + + if (version >= 29) { + // now compress the whole thing + compress(os_raw.str(), os_compressed, version, compression_level); + } } void MapBlock::serializeNetworkSpecific(std::ostream &os) @@ -449,7 +474,7 @@ void MapBlock::serializeNetworkSpecific(std::ostream &os) writeU8(os, 2); // version } -void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) +void MapBlock::deSerialize(std::istream &in_compressed, u8 version, bool disk) { if(!ser_ver_supported(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); @@ -460,10 +485,16 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) if(version <= 21) { - deSerialize_pre22(is, version, disk); + deSerialize_pre22(in_compressed, version, disk); return; } + // Decompress the whole block (version >= 29) + std::stringstream in_raw(std::ios_base::binary | std::ios_base::in | std::ios_base::out); + if (version >= 29) + decompress(in_compressed, in_raw, version); + std::istream &is = version >= 29 ? in_raw : in_compressed; + u8 flags = readU8(is); is_underground = (flags & 0x01) != 0; m_day_night_differs = (flags & 0x02) != 0; @@ -473,9 +504,20 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) m_lighting_complete = readU16(is); m_generated = (flags & 0x08) == 0; - /* - Bulk node data - */ + NameIdMapping nimap; + if (disk && version >= 29) { + // Timestamp + TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) + <<": Timestamp"<<std::endl); + setTimestampNoChangedFlag(readU32(is)); + m_disk_timestamp = m_timestamp; + + // Node/id mapping + TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) + <<": NameIdMapping"<<std::endl); + nimap.deSerialize(is); + } + TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Bulk node data"<<std::endl); u8 content_width = readU8(is); @@ -484,29 +526,44 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) throw SerializationError("MapBlock::deSerialize(): invalid content_width"); if(params_width != 2) throw SerializationError("MapBlock::deSerialize(): invalid params_width"); - MapNode::deSerializeBulk(is, version, data, nodecount, + + /* + Bulk node data + */ + if (version >= 29) { + MapNode::deSerializeBulk(is, version, data, nodecount, content_width, params_width); + } else { + // use in_raw from above to avoid allocating another stream object + decompress(is, in_raw, version); + MapNode::deSerializeBulk(in_raw, version, data, nodecount, + content_width, params_width); + } /* NodeMetadata */ TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) <<": Node metadata"<<std::endl); - // Ignore errors - try { - std::ostringstream oss(std::ios_base::binary); - decompressZlib(is, oss); - std::istringstream iss(oss.str(), std::ios_base::binary); - if (version >= 23) - m_node_metadata.deSerialize(iss, m_gamedef->idef()); - else - content_nodemeta_deserialize_legacy(iss, - &m_node_metadata, &m_node_timers, - m_gamedef->idef()); - } catch(SerializationError &e) { - warningstream<<"MapBlock::deSerialize(): Ignoring an error" - <<" while deserializing node metadata at (" - <<PP(getPos())<<": "<<e.what()<<std::endl; + if (version >= 29) { + m_node_metadata.deSerialize(is, m_gamedef->idef()); + } else { + try { + // reuse in_raw + in_raw.str(""); + in_raw.clear(); + decompress(is, in_raw, version); + if (version >= 23) + m_node_metadata.deSerialize(in_raw, m_gamedef->idef()); + else + content_nodemeta_deserialize_legacy(in_raw, + &m_node_metadata, &m_node_timers, + m_gamedef->idef()); + } catch(SerializationError &e) { + warningstream<<"MapBlock::deSerialize(): Ignoring an error" + <<" while deserializing node metadata at (" + <<PP(getPos())<<": "<<e.what()<<std::endl; + } } /* @@ -530,17 +587,20 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) <<": Static objects"<<std::endl); m_static_objects.deSerialize(is); - // Timestamp - TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) - <<": Timestamp"<<std::endl); - setTimestampNoChangedFlag(readU32(is)); - m_disk_timestamp = m_timestamp; + if(version < 29) { + // Timestamp + TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) + <<": Timestamp"<<std::endl); + setTimestampNoChangedFlag(readU32(is)); + m_disk_timestamp = m_timestamp; + + // Node/id mapping + TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) + <<": NameIdMapping"<<std::endl); + nimap.deSerialize(is); + } // Dynamically re-set ids based on node names - TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos()) - <<": NameIdMapping"<<std::endl); - NameIdMapping nimap; - nimap.deSerialize(is); correctBlockNodeIds(&nimap, data, m_gamedef); if(version >= 25){ |