Пример #1
0
void CNodeDefManager::removeNode(const std::string &name)
{
	// Pre-condition
	assert(name != "");

	// Erase name from name ID mapping
	content_t id = CONTENT_IGNORE;
	if (m_name_id_mapping.getId(name, id)) {
		m_name_id_mapping.eraseName(name);
		m_name_id_mapping_with_aliases.erase(name);
	}

	// Erase node content from all groups it belongs to
	for (std::unordered_map<std::string, std::vector<content_t>>::iterator iter_groups =
			m_group_to_items.begin(); iter_groups != m_group_to_items.end();) {
		std::vector<content_t> &items = iter_groups->second;
		items.erase(std::remove(items.begin(), items.end(), id), items.end());

		// Check if group is empty
		if (items.empty())
			m_group_to_items.erase(iter_groups++);
		else
			++iter_groups;
	}
}
Пример #2
0
void MapBlock::serializeDiskExtra(std::ostream &os, u8 version)
{
	// Versions up from 9 have block objects. (DEPRECATED)
	if(version >= 9)
	{
		// count=0
		writeU16(os, 0);
	}
	
	// Versions up from 15 have static objects.
	if(version >= 15)
	{
		m_static_objects.serialize(os);
	}

	// Timestamp
	if(version >= 17)
	{
		writeU32(os, getTimestamp());
	}

	// Scan and write node definition id mapping
	if(version >= 21){
		NameIdMapping nimap;
		getBlockNodeIdMapping(&nimap, this, m_gamedef->ndef());
		nimap.serialize(os);
	}
}
Пример #3
0
void CNodeDefManager::removeNode(const std::string &name)
{
	// Pre-condition
	assert(name != "");

	// Erase name from name ID mapping
	content_t id = CONTENT_IGNORE;
	if (m_name_id_mapping.getId(name, id)) {
		m_name_id_mapping.eraseName(name);
		m_name_id_mapping_with_aliases.erase(name);
	}

	// Erase node content from all groups it belongs to
	for (UNORDERED_MAP<std::string, GroupItems>::iterator iter_groups =
			m_group_to_items.begin();
			iter_groups != m_group_to_items.end();) {
		GroupItems &items = iter_groups->second;
		for (GroupItems::iterator iter_groupitems = items.begin();
				iter_groupitems != items.end();) {
			if (iter_groupitems->first == id)
				items.erase(iter_groupitems++);
			else
				iter_groupitems++;
		}

		// Check if group is empty
		if (items.size() == 0)
			m_group_to_items.erase(iter_groups++);
		else
			iter_groups++;
	}
}
Пример #4
0
void MapBlock::deSerializeDiskExtra(std::istream &is, u8 version)
{
	/*
		Versions up from 9 have block objects. (DEPRECATED)
	*/
	if(version >= 9){
		u16 count = readU16(is);
		// Not supported and length not known if count is not 0
		if(count != 0){
			errorstream<<"WARNING: MapBlock::deSerializeDiskExtra(): "
					<<"Ignoring stuff coming at and after MBOs"<<std::endl;
			return;
		}
	}

	/*
		Versions up from 15 have static objects.
	*/
	if(version >= 15)
		m_static_objects.deSerialize(is);
		
	// Timestamp
	if(version >= 17){
		setTimestamp(readU32(is));
		m_disk_timestamp = m_timestamp;
	} else {
		setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
	}
	
	// Dynamically re-set ids based on node names
	NameIdMapping nimap;
	// If supported, read node definition id mapping
	if(version >= 21){
		nimap.deSerialize(is);
	// Else set the legacy mapping
	} else {
		content_mapnode_get_name_id_mapping(&nimap);
	}
	correctBlockNodeIds(&nimap, this, m_gamedef);
}
Пример #5
0
// IWritableNodeDefManager
content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
{
	// Pre-conditions
	if (name == "")
		return CONTENT_IGNORE;
	if (name != def.name)
		return CONTENT_IGNORE;

	// Don't allow redefining ignore (but allow air and unknown)
	if (name == "ignore") {
		infostream << "NodeDefManager: WARNING: Ignoring "
			"CONTENT_IGNORE redefinition"<<std::endl;
		return CONTENT_IGNORE;
	}

	content_t id = CONTENT_IGNORE;
	if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
		// Get new id
		id = allocateId();
		if (id == CONTENT_IGNORE) {
			infostream << "NodeDefManager: WARNING: Absolute "
				"limit reached" << std::endl;
			return CONTENT_IGNORE;
		}
		if (id == CONTENT_IGNORE)
			return CONTENT_IGNORE;
		addNameIdMapping(id, name);
	}
	m_content_features[id] = def;
	verbosestream << "NodeDefManager: registering content id \"" << id
		<< "\": name=\"" << def.name << "\""<<std::endl;

	// Add this content to the list of all groups it belongs to
	// FIXME: This should remove a node from groups it no longer
	// belongs to when a node is re-registered
	for (ItemGroupList::const_iterator i = def.groups.begin();
		i != def.groups.end(); ++i) {
		std::string group_name = i->first;

		std::map<std::string, GroupItems>::iterator
			j = m_group_to_items.find(group_name);
		if (j == m_group_to_items.end()) {
			m_group_to_items[group_name].push_back(
				std::make_pair(id, i->second));
		} else {
			GroupItems &items = j->second;
			items.push_back(std::make_pair(id, i->second));
		}
	}
	return id;
}
Пример #6
0
void CNodeDefManager::updateAliases(IItemDefManager *idef)
{
	std::set<std::string> all;
	idef->getAll(all);
	m_name_id_mapping_with_aliases.clear();
	for (const std::string &name : all) {
		const std::string &convert_to = idef->getAlias(name);
		content_t id;
		if (m_name_id_mapping.getId(convert_to, id)) {
			m_name_id_mapping_with_aliases.insert(
				std::make_pair(name, id));
		}
	}
}
Пример #7
0
void CNodeDefManager::updateAliases(IItemDefManager *idef)
{
	std::set<std::string> all = idef->getAll();
	m_name_id_mapping_with_aliases.clear();
	for (std::set<std::string>::iterator
			i = all.begin(); i != all.end(); ++i) {
		std::string name = *i;
		std::string convert_to = idef->getAlias(name);
		content_t id;
		if (m_name_id_mapping.getId(convert_to, id)) {
			m_name_id_mapping_with_aliases.insert(
				std::make_pair(name, id));
		}
	}
}
Пример #8
0
void CNodeDefManager::deSerialize(std::istream &is)
{
	clear();
	int version = readU8(is);
	if (version != 1)
		throw SerializationError("unsupported NodeDefinitionManager version");
	u16 count = readU16(is);
	std::istringstream is2(deSerializeLongString(is), std::ios::binary);
	ContentFeatures f;
	for (u16 n = 0; n < count; n++) {
		u16 i = readU16(is2);

		// Read it from the string wrapper
		std::string wrapper = deSerializeString(is2);
		std::istringstream wrapper_is(wrapper, std::ios::binary);
		f.deSerialize(wrapper_is);

		// Check error conditions
		if (i == CONTENT_IGNORE || i == CONTENT_AIR || i == CONTENT_UNKNOWN) {
			warningstream << "NodeDefManager::deSerialize(): "
				"not changing builtin node " << i << std::endl;
			continue;
		}
		if (f.name.empty()) {
			warningstream << "NodeDefManager::deSerialize(): "
				"received empty name" << std::endl;
			continue;
		}

		// Ignore aliases
		u16 existing_id;
		if (m_name_id_mapping.getId(f.name, existing_id) && i != existing_id) {
			warningstream << "NodeDefManager::deSerialize(): "
				"already defined with different ID: " << f.name << std::endl;
			continue;
		}

		// All is ok, add node definition with the requested ID
		if (i >= m_content_features.size())
			m_content_features.resize((u32)(i) + 1);
		m_content_features[i] = f;
		addNameIdMapping(i, f.name);
		verbosestream << "deserialized " << f.name << std::endl;

		getNodeBoxUnion(f.selection_box, f, &m_selection_box_union);
		fixSelectionBoxIntUnion();
	}
}
Пример #9
0
void CNodeDefManager::msgpack_unpack(msgpack::object o)
{
	clear();

	std::map<int, ContentFeatures> unpacked_features;
	o.convert(&unpacked_features);

	for (std::map<int, ContentFeatures>::iterator it = unpacked_features.begin();
			it != unpacked_features.end(); ++it) {
		unsigned int i = it->first;
		ContentFeatures f = it->second;

		if(i == CONTENT_IGNORE || i == CONTENT_AIR
				|| i == CONTENT_UNKNOWN){
			infostream<<"NodeDefManager::deSerialize(): WARNING: "
				<<"not changing builtin node "<<i
				<<std::endl;
			continue;
		}
		if(f.name == ""){
			infostream<<"NodeDefManager::deSerialize(): WARNING: "
				<<"received empty name"<<std::endl;
			continue;
		}
		u16 existing_id;
		bool found = m_name_id_mapping.getId(f.name, existing_id);  // ignore aliases
		if(found && i != existing_id){
			infostream<<"NodeDefManager::deSerialize(): WARNING: "
				<<"already defined with different ID: "
				<<f.name<<std::endl;
			continue;
		}

		// All is ok, add node definition with the requested ID
		if(i >= m_content_features.size())
			m_content_features.resize((u32)(i) + 1);
		m_content_features[i] = f;
		addNameIdMapping(i, f.name);
		verbosestream<<"deserialized "<<f.name<<std::endl;
	}
}
Пример #10
0
// IWritableNodeDefManager
content_t CNodeDefManager::set(const std::string &name, const ContentFeatures &def)
{
	// Pre-conditions
	assert(name != "");
	assert(name == def.name);

	// Don't allow redefining ignore (but allow air and unknown)
	if (name == "ignore") {
		warningstream << "NodeDefManager: Ignoring "
			"CONTENT_IGNORE redefinition"<<std::endl;
		return CONTENT_IGNORE;
	}

	content_t id = CONTENT_IGNORE;
	if (!m_name_id_mapping.getId(name, id)) { // ignore aliases
		// Get new id
		id = allocateId();
		if (id == CONTENT_IGNORE) {
			warningstream << "NodeDefManager: Absolute "
				"limit reached" << std::endl;
			return CONTENT_IGNORE;
		}
		assert(id != CONTENT_IGNORE);
		addNameIdMapping(id, name);
	}
	m_content_features[id] = def;
	verbosestream << "NodeDefManager: registering content id \"" << id
		<< "\": name=\"" << def.name << "\""<<std::endl;

	getNodeBoxUnion(def.selection_box, def, &m_selection_box_union);
	fixSelectionBoxIntUnion();
	// Add this content to the list of all groups it belongs to
	// FIXME: This should remove a node from groups it no longer
	// belongs to when a node is re-registered
	for (const auto &group : def.groups) {
		const std::string &group_name = group.first;
		m_group_to_items[group_name].push_back(id);
	}
	return id;
}
Пример #11
0
void CNodeDefManager::clear()
{
	m_content_features.clear();
	m_name_id_mapping.clear();
	m_name_id_mapping_with_aliases.clear();
	m_group_to_items.clear();
	m_next_id = 0;

	resetNodeResolveState();

	u32 initial_length = 0;
	initial_length = MYMAX(initial_length, CONTENT_UNKNOWN + 1);
	initial_length = MYMAX(initial_length, CONTENT_AIR + 1);
	initial_length = MYMAX(initial_length, CONTENT_IGNORE + 1);
	m_content_features.resize(initial_length);

	// Set CONTENT_UNKNOWN
	{
		ContentFeatures f;
		f.name = "unknown";
		// Insert directly into containers
		content_t c = CONTENT_UNKNOWN;
		m_content_features[c] = f;
		addNameIdMapping(c, f.name);
	}

	// Set CONTENT_AIR
	{
		ContentFeatures f;
		f.name                = "air";
		f.drawtype            = NDT_AIRLIKE;
		f.param_type          = CPT_LIGHT;
		f.light_propagates    = true;
		f.sunlight_propagates = true;
		f.walkable            = false;
		f.pointable           = false;
		f.diggable            = false;
		f.buildable_to        = true;
		f.floodable           = true;
		f.is_ground_content   = true;
		// Insert directly into containers
		content_t c = CONTENT_AIR;
		m_content_features[c] = f;
		addNameIdMapping(c, f.name);
	}

	// Set CONTENT_IGNORE
	{
		ContentFeatures f;
		f.name                = "ignore";
		f.drawtype            = NDT_AIRLIKE;
		f.param_type          = CPT_NONE;
		f.light_propagates    = false;
		f.sunlight_propagates = false;
		f.walkable            = false;
		f.pointable           = false;
		f.diggable            = false;
		f.buildable_to        = true; // A way to remove accidental CONTENT_IGNOREs
		f.is_ground_content   = true;
		// Insert directly into containers
		content_t c = CONTENT_IGNORE;
		m_content_features[c] = f;
		addNameIdMapping(c, f.name);
	}
}
Пример #12
0
void CNodeDefManager::addNameIdMapping(content_t i, std::string name)
{
	m_name_id_mapping.set(i, name);
	m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
}
Пример #13
0
void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
{
	auto lock = lock_shared_rec();
	if(!ser_ver_supported(version))
		throw VersionMismatchException("ERROR: MapBlock format not supported");

	if(data == NULL)
	{
		throw SerializationError("ERROR: Not writing dummy block.");
	}

	FATAL_ERROR_IF(version < SER_FMT_CLIENT_VER_LOWEST, "Serialize version error");

	// First byte
	u8 flags = 0;
	if(is_underground)
		flags |= 0x01;
	if(getDayNightDiff())
		flags |= 0x02;
	if(m_lighting_expired)
		flags |= 0x04;
	if(m_generated == false)
	{
		flags |= 0x08;
		infostream<<" serialize not generated block"<<std::endl;
	}

	writeU8(os, flags);

	/*
		Bulk node data
	*/
	NameIdMapping nimap;
	u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
	if(disk)
	{
		MapNode *tmp_nodes = new MapNode[nodecount];
		for(u32 i=0; i<nodecount; i++)
			tmp_nodes[i] = data[i];
		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, true);
		delete[] tmp_nodes;
	}
	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, 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)
	{
		if(version <= 24){
			// Node timers
			m_node_timers.serialize(os, version);
		}

		// Static objects
		m_static_objects.serialize(os);

		// Timestamp
		writeU32(os, getTimestamp());

		// Write block-specific node definition id mapping
		nimap.serialize(os);

		if(version >= 25){
			// Node timers
			m_node_timers.serialize(os, version);
		}
	}
}
Пример #14
0
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)
		{
			tmp_data[i].setParam1(tmp_data[i].getParam2());
			tmp_data[i].setParam2(0);
		}
		// wall_mounted
		if(f.legacy_wallmounted)
		{
			u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0};
			u8 dir_new_format = tmp_data[i].getParam2() & 7; // lowest 3 bits
			u8 dir_old_format = wallmounted_new_to_old[dir_new_format];
			tmp_data[i].setParam2(dir_old_format);
		}
	}

	// Serialize nodes
	u32 ser_length = MapNode::serializedLength(version);
	SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);
	for(u32 i=0; i<nodecount; i++)
	{
		tmp_data[i].serialize(&databuf_nodelist[i*ser_length], version);
	}

	delete[] tmp_data;
		
	// These have no compression
	if(version <= 3 || version == 5 || version == 6)
	{
		writeU8(os, is_underground);
		os.write((char*)*databuf_nodelist, databuf_nodelist.getSize());
	}
	else if(version <= 10)
	{
		/*
			With compression.
			Compress the materials and the params separately.
		*/
		
		// First byte
		writeU8(os, is_underground);

		// Get and compress materials
		SharedBuffer<u8> materialdata(nodecount);
		for(u32 i=0; i<nodecount; i++)
		{
			materialdata[i] = databuf_nodelist[i*ser_length];
		}
		compress(materialdata, os, version);

		// Get and compress lights
		SharedBuffer<u8> lightdata(nodecount);
		for(u32 i=0; i<nodecount; i++)
		{
			lightdata[i] = databuf_nodelist[i*ser_length+1];
		}
		compress(lightdata, os, version);
		
		if(version >= 10)
		{
			// Get and compress param2
			SharedBuffer<u8> param2data(nodecount);
			for(u32 i=0; i<nodecount; i++)
			{
				param2data[i] = databuf_nodelist[i*ser_length+2];
			}
			compress(param2data, os, version);
		}
	}
	// All other versions (newest)
	else
	{
		// First byte
		u8 flags = 0;
		if(is_underground)
			flags |= 0x01;
		if(m_day_night_differs)
			flags |= 0x02;
		if(m_lighting_expired)
			flags |= 0x04;
		if(version >= 18)
		{
			if(m_generated == false)
				flags |= 0x08;
		}
		writeU8(os, flags);
		
		/*
			Get data
		*/

		// Create buffer with different parameters sorted
		SharedBuffer<u8> databuf(nodecount*3);
		for(u32 i=0; i<nodecount; i++)
		{
			databuf[i] = databuf_nodelist[i*ser_length];
			databuf[i+nodecount] = databuf_nodelist[i*ser_length+1];
			databuf[i+nodecount*2] = databuf_nodelist[i*ser_length+2];
		}

		/*
			Compress data to output stream
		*/

		compress(databuf, os, version);
		
		/*
			NodeMetadata
		*/
		if(version >= 14)
		{
			if(version <= 15)
			{
				try{
					std::ostringstream oss(std::ios_base::binary);
					m_node_metadata->serialize(oss);
					os<<serializeString(oss.str());
				}
				// This will happen if the string is longer than 65535
				catch(SerializationError &e)
				{
					// Use an empty string
					os<<serializeString("");
				}
			}
			else
			{
				std::ostringstream oss(std::ios_base::binary);
				m_node_metadata->serialize(oss);
				compressZlib(oss.str(), os);
				//os<<serializeLongString(oss.str());
			}
		}
	}


	if(disk)
	{
		// Versions up from 9 have block objects. (DEPRECATED)
		if(version >= 9)
		{
			// count=0
			writeU16(os, 0);
		}

		// Versions up from 15 have static objects.
		if(version >= 15)
		{
			m_static_objects.serialize(os);
		}

		// Timestamp
		if(version >= 17)
		{
			writeU32(os, getTimestamp());
		}

		// Scan and write node definition id mapping
		if(version >= 21)
		{
			NameIdMapping nimap;
			getBlockNodeIdMapping_pre22(&nimap, data, m_gamedef->ndef());
			nimap.serialize(os);
		}
	}
}
Пример #15
0
void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
{
	if(!ser_ver_supported(version))
		throw VersionMismatchException("ERROR: MapBlock format not supported");
	
	if(data == NULL)
	{
		throw SerializationError("ERROR: Not writing dummy block.");
	}
	
	if(version <= 21)
	{
		serialize_pre22(os, version, disk);
		return;
	}

	// First byte
	u8 flags = 0;
	if(is_underground)
		flags |= 0x01;
	if(m_day_night_differs)
		flags |= 0x02;
	if(m_lighting_expired)
		flags |= 0x04;
	if(m_generated == false)
		flags |= 0x08;
	writeU8(os, flags);
	
	/*
		Bulk node data
	*/
	NameIdMapping nimap;
	u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
	if(disk)
	{
		MapNode *tmp_nodes = new MapNode[nodecount];
		for(u32 i=0; i<nodecount; i++)
			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);
	}
}
Пример #16
0
void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
{
	if(!ser_ver_supported(version))
		throw VersionMismatchException("ERROR: MapBlock format not supported");
	
	if(data == NULL)
	{
		throw SerializationError("ERROR: Not writing dummy block.");
	}
	
	// Can't do this anymore; we have 16-bit dynamically allocated node IDs
	// in memory; conversion just won't work in this direction.
	if(version < 24)
		throw SerializationError("MapBlock::serialize: serialization to "
				"version < 24 not possible");
		
	// First byte
	u8 flags = 0;
	if(is_underground)
		flags |= 0x01;
	if(getDayNightDiff())
		flags |= 0x02;
	if(m_lighting_expired)
		flags |= 0x04;
	if(m_generated == false)
		flags |= 0x08;
	writeU8(os, flags);
	
	/*
		Bulk node data
	*/
	NameIdMapping nimap;
	u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
	if(disk)
	{
		MapNode *tmp_nodes = new MapNode[nodecount];
		for(u32 i=0; i<nodecount; i++)
			tmp_nodes[i] = data[i];
		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, true);
		delete[] tmp_nodes;
	}
	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, 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)
	{
		// Node timers
		m_node_timers.serialize(os);

		// Static objects
		m_static_objects.serialize(os);

		// Timestamp
		writeU32(os, getTimestamp());

		// Write block-specific node definition id mapping
		nimap.serialize(os);
	}
}
Пример #17
0
void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
{
	if(!ser_ver_supported(version))
		throw VersionMismatchException("ERROR: MapBlock format not supported");
	
	TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())<<std::endl);

	m_day_night_differs_expired = false;

	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
	*/
	TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
			<<": Bulk node data"<<std::endl);
	u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
	u8 content_width = readU8(is);
	u8 params_width = readU8(is);
	if(content_width != 1 && content_width != 2)
		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
	*/
	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);
		else
			content_nodemeta_deserialize_legacy(iss,
					&m_node_metadata, &m_node_timers,
					m_gamedef);
	}
	catch(SerializationError &e)
	{
		errorstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error"
				<<" while deserializing node metadata at ("
				<<PP(getPos())<<": "<<e.what()<<std::endl;
	}

	/*
		Data that is only on disk
	*/
	if(disk)
	{
		// Node timers
		if(version == 23){
			// Read unused zero
			readU8(is);
		}
		else if(version >= 24){
			TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
					<<": Node timers"<<std::endl);
			m_node_timers.deSerialize(is);
		}

		// Static objects
		TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
				<<": Static objects"<<std::endl);
		m_static_objects.deSerialize(is);
		
		// Timestamp
		TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
				<<": Timestamp"<<std::endl);
		setTimestamp(readU32(is));
		m_disk_timestamp = m_timestamp;
		
		// 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);
	}
Пример #18
0
void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
{
	u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;

	// Initialize default flags
	is_underground = false;
	m_day_night_differs = false;
	m_lighting_expired = false;
	m_generated = true;

	// Make a temporary buffer
	u32 ser_length = MapNode::serializedLength(version);
	SharedBuffer<u8> databuf_nodelist(nodecount * ser_length);

	// These have no compression
	if(version <= 3 || version == 5 || version == 6)
	{
		char tmp;
		is.read(&tmp, 1);
		if(is.gcount() != 1)
			throw SerializationError
					("MapBlock::deSerialize: no enough input data");
		is_underground = tmp;
		is.read((char*)*databuf_nodelist, nodecount * ser_length);
		if(is.gcount() != nodecount * ser_length)
			throw SerializationError
					("MapBlock::deSerialize: no enough input data");
	}
	else if(version <= 10)
	{
		u8 t8;
		is.read((char*)&t8, 1);
		is_underground = t8;

		{
			// Uncompress and set material data
			std::ostringstream os(std::ios_base::binary);
			decompress(is, os, version);
			std::string s = os.str();
			if(s.size() != nodecount)
				throw SerializationError
						("MapBlock::deSerialize: invalid format");
			for(u32 i=0; i<s.size(); i++)
			{
				databuf_nodelist[i*ser_length] = s[i];
			}
		}
		{
			// Uncompress and set param data
			std::ostringstream os(std::ios_base::binary);
			decompress(is, os, version);
			std::string s = os.str();
			if(s.size() != nodecount)
				throw SerializationError
						("MapBlock::deSerialize: invalid format");
			for(u32 i=0; i<s.size(); i++)
			{
				databuf_nodelist[i*ser_length + 1] = s[i];
			}
		}
	
		if(version >= 10)
		{
			// Uncompress and set param2 data
			std::ostringstream os(std::ios_base::binary);
			decompress(is, os, version);
			std::string s = os.str();
			if(s.size() != nodecount)
				throw SerializationError
						("MapBlock::deSerialize: invalid format");
			for(u32 i=0; i<s.size(); i++)
			{
				databuf_nodelist[i*ser_length + 2] = s[i];
			}
		}
	}
	// All other versions (newest)
	else
	{
		u8 flags;
		is.read((char*)&flags, 1);
		is_underground = (flags & 0x01) ? true : false;
		m_day_night_differs = (flags & 0x02) ? true : false;
		m_lighting_expired = (flags & 0x04) ? true : false;
		if(version >= 18)
			m_generated = (flags & 0x08) ? false : true;

		// Uncompress data
		std::ostringstream os(std::ios_base::binary);
		decompress(is, os, version);
		std::string s = os.str();
		if(s.size() != nodecount*3)
			throw SerializationError
					("MapBlock::deSerialize: decompress resulted in size"
					" other than nodecount*3");

		// deserialize nodes from buffer
		for(u32 i=0; i<nodecount; i++)
		{
			databuf_nodelist[i*ser_length] = s[i];
			databuf_nodelist[i*ser_length + 1] = s[i+nodecount];
			databuf_nodelist[i*ser_length + 2] = s[i+nodecount*2];
		}
		
		/*
			NodeMetadata
		*/
		if(version >= 14)
		{
			// Ignore errors
			try{
				if(version <= 15)
				{
					std::string data = deSerializeString(is);
					std::istringstream iss(data, std::ios_base::binary);
					m_node_metadata->deSerialize(iss, m_gamedef);
				}
				else
				{
					//std::string data = deSerializeLongString(is);
					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;
			}
		}
	}

	// Deserialize node data
	for(u32 i=0; i<nodecount; i++)
	{
		data[i].deSerialize(&databuf_nodelist[i*ser_length], version);
	}

	if(disk)
	{
		/*
			Versions up from 9 have block objects. (DEPRECATED)
		*/
		if(version >= 9){
			u16 count = readU16(is);
			// Not supported and length not known if count is not 0
			if(count != 0){
				errorstream<<"WARNING: MapBlock::deSerialize_pre22(): "
						<<"Ignoring stuff coming at and after MBOs"<<std::endl;
				return;
			}
		}

		/*
			Versions up from 15 have static objects.
		*/
		if(version >= 15)
			m_static_objects.deSerialize(is);

		// Timestamp
		if(version >= 17){
			setTimestamp(readU32(is));
			m_disk_timestamp = m_timestamp;
		} else {
			setTimestamp(BLOCK_TIMESTAMP_UNDEFINED);
		}

		// Dynamically re-set ids based on node names
		NameIdMapping nimap;
		// If supported, read node definition id mapping
		if(version >= 21){
			nimap.deSerialize(is);
		// Else set the legacy mapping
		} else {
			content_mapnode_get_name_id_mapping(&nimap);
		}
		correctBlockNodeIds(&nimap, data, m_gamedef);
	}


	// Legacy data changes
	// This code has to convert from pre-22 to post-22 format.
	INodeDefManager *nodedef = m_gamedef->ndef();
	for(u32 i=0; i<nodecount; i++)
	{
		const ContentFeatures &f = nodedef->get(data[i].getContent());
		// Mineral
		if(nodedef->getId("default:stone") == data[i].getContent()
				&& data[i].getParam1() == 1)
		{
			data[i].setContent(nodedef->getId("default:stone_with_coal"));
			data[i].setParam1(0);
		}
		else if(nodedef->getId("default:stone") == data[i].getContent()
				&& data[i].getParam1() == 2)
		{
			data[i].setContent(nodedef->getId("default:stone_with_iron"));
			data[i].setParam1(0);
		}
		// facedir_simple
		if(f.legacy_facedir_simple)
		{
			data[i].setParam2(data[i].getParam1());
			data[i].setParam1(0);
		}
		// wall_mounted
		if(f.legacy_wallmounted)
		{
			u8 wallmounted_new_to_old[8] = {0x04, 0x08, 0x01, 0x02, 0x10, 0x20, 0, 0};
			u8 dir_old_format = data[i].getParam2();
			u8 dir_new_format = 0;
			for(u8 j=0; j<8; j++)
			{
				if((dir_old_format & wallmounted_new_to_old[j]) != 0)
				{
					dir_new_format = j;
					break;
				}
			}
			data[i].setParam2(dir_new_format);
		}
	}

}