+ tmp_nodes[i] = data[i];
+ getBlockNodeIdMapping(&nimap, tmp_nodes, m_gamedef->ndef());
+
+ u8 content_width = 1;
+ /*u8 content_width = (nimap.size() <= 255) ? 1 : 2;*/
+ u8 params_width = 2;
+ writeU8(os, content_width);
+ writeU8(os, params_width);
+ MapNode::serializeBulk(os, version, tmp_nodes, nodecount,
+ content_width, params_width, true);
+ delete[] tmp_nodes;
+ }
+ else
+ {
+ u8 content_width = 1;
+ /*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, true);
+ }
+
+ /*
+ Node metadata
+ */
+ std::ostringstream oss(std::ios_base::binary);
+ m_node_metadata->serialize(oss);
+ compressZlib(oss.str(), os);
+
+ /*
+ Data that goes to disk, but not the network
+ */
+ if(disk)
+ {
+ // Static objects
+ m_static_objects.serialize(os);
+
+ // Timestamp
+ writeU32(os, getTimestamp());
+
+ // Write block-specific node definition id mapping
+ nimap.serialize(os);
+ }
+}
+
+
+void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
+{
+ if(!ser_ver_supported(version))
+ throw VersionMismatchException("ERROR: MapBlock format not supported");
+
+ if(version <= 21)
+ {
+ deSerialize_pre22(is, version, disk);
+ return;
+ }
+
+ u8 flags = readU8(is);
+ is_underground = (flags & 0x01) ? true : false;
+ m_day_night_differs = (flags & 0x02) ? true : false;
+ m_lighting_expired = (flags & 0x04) ? true : false;
+ m_generated = (flags & 0x08) ? false : true;
+
+ /*
+ Bulk node data
+ */
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+ u8 content_width = readU8(is);
+ u8 params_width = readU8(is);
+ if(content_width != 1)
+ throw SerializationError("MapBlock::deSerialize(): invalid content_width");
+ if(params_width != 2)
+ throw SerializationError("MapBlock::deSerialize(): invalid params_width");
+ MapNode::deSerializeBulk(is, version, data, nodecount,
+ content_width, params_width, true);
+
+ /*
+ NodeMetadata
+ */
+ // Ignore errors
+ try{
+ std::ostringstream oss(std::ios_base::binary);
+ decompressZlib(is, oss);
+ std::istringstream iss(oss.str(), std::ios_base::binary);
+ m_node_metadata->deSerialize(iss, m_gamedef);
+ }
+ catch(SerializationError &e)
+ {
+ errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
+ <<" while deserializing node metadata"<<std::endl;
+ }
+
+ /*
+ Data that is only on disk
+ */
+ if(disk)
+ {
+ // Static objects
+ m_static_objects.deSerialize(is);
+
+ // Timestamp
+ setTimestamp(readU32(is));
+ m_disk_timestamp = m_timestamp;
+
+ // Dynamically re-set ids based on node names
+ NameIdMapping nimap;
+ nimap.deSerialize(is);
+ correctBlockNodeIds(&nimap, data, m_gamedef);
+ }
+}
+
+/*
+ Legacy serialization
+*/
+
+// List relevant id-name pairs for ids in the block using nodedef
+// Before serialization version 22
+static void getBlockNodeIdMapping_pre22(NameIdMapping *nimap, MapNode *nodes,
+ INodeDefManager *nodedef)
+{
+ std::set<content_t> unknown_contents;
+ for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
+ {
+ content_t id = nodes[i].getContent();
+ const ContentFeatures &f = nodedef->get(id);
+ const std::string &name = f.name;
+ if(name == "")
+ unknown_contents.insert(id);
+ else
+ nimap->set(id, name);
+ }
+ for(std::set<content_t>::const_iterator
+ i = unknown_contents.begin();
+ i != unknown_contents.end(); i++){
+ errorstream<<"getBlockNodeIdMapping_pre22(): IGNORING ERROR: "
+ <<"Name for node id "<<(*i)<<" not known"<<std::endl;
+ }
+}
+void MapBlock::serialize_pre22(std::ostream &os, u8 version, bool disk)
+{
+ u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
+
+ MapNode *tmp_data = new MapNode[nodecount];
+
+ // Legacy data changes
+ // This code has to change from post-22 to pre-22 format.
+ INodeDefManager *nodedef = m_gamedef->ndef();
+ for(u32 i=0; i<nodecount; i++)
+ {
+ const ContentFeatures &f = nodedef->get(tmp_data[i].getContent());
+ // Mineral
+ if(nodedef->getId("default:stone_with_coal") == tmp_data[i].getContent())
+ {
+ tmp_data[i].setContent(nodedef->getId("default:stone"));
+ tmp_data[i].setParam1(1); // MINERAL_COAL
+ }
+ else if(nodedef->getId("default:stone_with_iron") == tmp_data[i].getContent())
+ {
+ tmp_data[i].setContent(nodedef->getId("default:stone"));
+ tmp_data[i].setParam1(2); // MINERAL_IRON
+ }
+ // facedir_simple
+ if(f.legacy_facedir_simple)