From: Perttu Ahola <celeron55@gmail.com>
Date: Mon, 23 Jul 2012 04:20:13 +0000 (+0300)
Subject: Fix map deserialization and remove old serialization code
X-Git-Tag: 0.4.2-rc1~34
X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=fd845f27f5b3e3c6587c472be76235567a7b934d;p=oweals%2Fminetest.git

Fix map deserialization and remove old serialization code
---

diff --git a/src/clientserver.h b/src/clientserver.h
index 521406844..d43220962 100644
--- a/src/clientserver.h
+++ b/src/clientserver.h
@@ -61,10 +61,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 		(some dev snapshot)
 		TOCLIENT_INVENTORY_FORMSPEC
 		(0.4.0, 0.4.1)
+	PROTOCOL_VERSION 12:
 		TOSERVER_INVENTORY_FIELDS
+		16-bit node ids
 */
 
-#define PROTOCOL_VERSION 11
+#define PROTOCOL_VERSION 12
 
 #define PROTOCOL_ID 0x4f457403
 
diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp
index 410aaa911..c3fdb4a42 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -102,23 +102,6 @@ content_t trans_table_19[21][2] = {
 	{CONTENT_BOOKSHELF, 29},
 };
 
-MapNode mapnode_translate_from_internal(MapNode n_from, u8 version)
-{
-	MapNode result = n_from;
-	if(version <= 19)
-	{
-		content_t c_from = n_from.getContent();
-		for(u32 i=0; i<sizeof(trans_table_19)/sizeof(trans_table_19[0]); i++)
-		{
-			if(trans_table_19[i][0] == c_from)
-			{
-				result.setContent(trans_table_19[i][1]);
-				break;
-			}
-		}
-	}
-	return result;
-}
 MapNode mapnode_translate_to_internal(MapNode n_from, u8 version)
 {
 	MapNode result = n_from;
diff --git a/src/content_mapnode.h b/src/content_mapnode.h
index cc11cd224..45c2b0763 100644
--- a/src/content_mapnode.h
+++ b/src/content_mapnode.h
@@ -28,7 +28,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 // Backwards compatibility for non-extended content types in v19
 extern content_t trans_table_19[21][2];
-MapNode mapnode_translate_from_internal(MapNode n_from, u8 version);
 MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
 
 // Get legacy node name mapping for loading old blocks
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index 571c2082d..c7c820d42 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -552,12 +552,12 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
 		throw SerializationError("ERROR: Not writing dummy block.");
 	}
 	
-	if(version <= 21)
-	{
-		serialize_pre22(os, version, disk);
-		return;
-	}
-
+	// 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)
@@ -582,7 +582,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
 			tmp_nodes[i] = data[i];
 		getBlockNodeIdMapping(&nimap, tmp_nodes, m_gamedef->ndef());
 
-		u8 content_width = (version < 24) ? 1 : 2;
+		u8 content_width = 2;
 		u8 params_width = 2;
 		writeU8(os, content_width);
 		writeU8(os, params_width);
@@ -604,10 +604,7 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
 		Node metadata
 	*/
 	std::ostringstream oss(std::ios_base::binary);
-	if(version >= 23)
-		m_node_metadata.serialize(oss);
-	else
-		content_nodemeta_serialize_legacy(oss, &m_node_metadata);
+	m_node_metadata.serialize(oss);
 	compressZlib(oss.str(), os);
 
 	/*
@@ -615,13 +612,8 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
 	*/
 	if(disk)
 	{
-		// Version 23 doesn't actually contain node timers
-		// (this field should have not been added)
-		if(version == 23)
-			writeU8(os, 0);
-		// Node timers are in version 24
-		if(version >= 24)
-			m_node_timers.serialize(os);
+		// Node timers
+		m_node_timers.serialize(os);
 
 		// Static objects
 		m_static_objects.serialize(os);
@@ -634,7 +626,6 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
 	}
 }
 
-
 void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
 {
 	if(!ser_ver_supported(version))
@@ -738,219 +729,6 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
 	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)
-		{
-			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(getDayNightDiff())
-			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);
-					content_nodemeta_serialize_legacy(oss, &m_node_metadata);
-					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);
-				content_nodemeta_serialize_legacy(oss, &m_node_metadata);
-				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);
-		}
-	}
-}
-
 void MapBlock::deSerialize_pre22(std::istream &is, u8 version, bool disk)
 {
 	u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
diff --git a/src/mapblock.h b/src/mapblock.h
index adb3324f6..7f901e5d3 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -467,7 +467,6 @@ private:
 		Private methods
 	*/
 
-	void serialize_pre22(std::ostream &os, u8 version, bool disk);
 	void deSerialize_pre22(std::istream &is, u8 version, bool disk);
 
 	/*
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 0479d2e55..c616e0117 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -241,28 +241,16 @@ void MapNode::serialize(u8 *dest, u8 version)
 {
 	if(!ser_ver_supported(version))
 		throw VersionMismatchException("ERROR: MapNode format not supported");
-
-	if(version <= 21)
-	{
-		serialize_pre22(dest, version);
-		return;
-	}
-
-	if(version >= 24){
-		writeU16(dest+0, param0);
-		writeU8(dest+2, param1);
-		writeU8(dest+3, param2);
-	}
-	else{
-		writeU8(dest+0, (param0&0xFF));
-		writeU8(dest+1, param1);
-		if (param0 > 0x7F){
-			writeU8(dest+2, ((param2&0x0F) | ((param0&0x0F00)>>4)));
-		}
-		else{
-			writeU8(dest+2, param2);
-		}
-	}
+	
+	// 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("MapNode::serialize: serialization to "
+				"version < 24 not possible");
+		
+	writeU16(dest+0, param0);
+	writeU8(dest+2, param1);
+	writeU8(dest+3, param2);
 }
 void MapNode::deSerialize(u8 *source, u8 version)
 {
@@ -297,22 +285,20 @@ void MapNode::serializeBulk(std::ostream &os, int version,
 	if(!ser_ver_supported(version))
 		throw VersionMismatchException("ERROR: MapNode format not supported");
 
-	assert(version >= 22);
-	assert(content_width == 1 || content_width == 2);
+	assert(content_width == 2);
 	assert(params_width == 2);
 
+	// 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("MapNode::serializeBulk: serialization to "
+				"version < 24 not possible");
+
 	SharedBuffer<u8> databuf(nodecount * (content_width + params_width));
 
 	// Serialize content
-	if(content_width == 1)
-	{
-		for(u32 i=0; i<nodecount; i++)
-			writeU8(&databuf[i], (nodes[i].param0&0x00FF));
-	}else if(content_width == 2)
-	{
-		for(u32 i=0; i<nodecount; i++)
-			writeU16(&databuf[i*2], nodes[i].param0);
-	}
+	for(u32 i=0; i<nodecount; i++)
+		writeU16(&databuf[i*2], nodes[i].param0);
 
 	// Serialize param1
 	u32 start1 = content_width * nodecount;
@@ -321,21 +307,8 @@ void MapNode::serializeBulk(std::ostream &os, int version,
 
 	// Serialize param2
 	u32 start2 = (content_width + 1) * nodecount;
-	if(content_width == 1)
-	{
-		for(u32 i=0; i<nodecount; i++) {
-			if(nodes[i].param0 > 0x7F){
-				writeU8(&databuf[start2 + i], ((nodes[i].param2&0x0F) | ((nodes[i].param0&0x0F00)>>4)));
-			}
-			else{
-				writeU8(&databuf[start2 + i], nodes[i].param2);
-			}
-		}
-	}else if(content_width == 2)
-	{
-		for(u32 i=0; i<nodecount; i++)
-			writeU8(&databuf[start2 + i], nodes[i].param2);
-	}
+	for(u32 i=0; i<nodecount; i++)
+		writeU8(&databuf[start2 + i], nodes[i].param2);
 
 	/*
 		Compress data to output stream
@@ -408,7 +381,8 @@ void MapNode::deSerializeBulk(std::istream &is, int version,
 		for(u32 i=0; i<nodecount; i++) {
 			nodes[i].param2 = readU8(&databuf[start2 + i]);
 			if(nodes[i].param0 > 0x7F){
-				nodes[i].param0 |= ((nodes[i].param2&0xF0)<<4);
+				nodes[i].param0 <<= 4;
+				nodes[i].param0 |= (nodes[i].param2&0xF0)>>4;
 				nodes[i].param2 &= 0x0F;
 			}
 		}
@@ -423,40 +397,6 @@ void MapNode::deSerializeBulk(std::istream &is, int version,
 /*
 	Legacy serialization
 */
-void MapNode::serialize_pre22(u8 *dest, u8 version)
-{
-	// Translate to wanted version
-	MapNode n_foreign = mapnode_translate_from_internal(*this, version);
-
-	u8 actual_param0 = n_foreign.param0;
-
-	// Convert special values from new version to old
-	if(version <= 18)
-	{
-		// In these versions, CONTENT_IGNORE and CONTENT_AIR
-		// are 255 and 254
-		if(actual_param0 == CONTENT_IGNORE)
-			actual_param0 = 255;
-		else if(actual_param0 == CONTENT_AIR)
-			actual_param0 = 254;
-	}
-
-	if(version == 0)
-	{
-		dest[0] = actual_param0;
-	}
-	else if(version <= 9)
-	{
-		dest[0] = actual_param0;
-		dest[1] = n_foreign.param1;
-	}
-	else
-	{
-		dest[0] = actual_param0;
-		dest[1] = n_foreign.param1;
-		dest[2] = n_foreign.param2;
-	}
-}
 void MapNode::deSerialize_pre22(u8 *source, u8 version)
 {
 	if(version <= 1)
@@ -473,6 +413,11 @@ void MapNode::deSerialize_pre22(u8 *source, u8 version)
 		param0 = source[0];
 		param1 = source[1];
 		param2 = source[2];
+		if(param0 > 0x7f){
+			param0 <<= 4;
+			param0 |= (param2&0xf0)>>4;
+			param2 &= 0x0f;
+		}
 	}
 	
 	// Convert special values from old version to new
diff --git a/src/mapnode.h b/src/mapnode.h
index fe656fa5c..a95497ef5 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -33,10 +33,6 @@ class INodeDefManager;
 	- Material = irrlicht's Material class
 	- Content = (content_t) content of a node
 	- Tile = TileSpec at some side of a node of some content type
-
-	Content ranges:
-	  0x000...0x07f: param2 is fully usable
-	  0x800...0xfff: param2 lower 4 bits are free
 */
 typedef u16 content_t;
 #define MAX_CONTENT 0xfff
@@ -84,8 +80,6 @@ struct MapNode
 {
 	/*
 		Main content
-		0x00-0x7f: Short content type
-		0x80-0xff: Long content type
 	*/
 	u16 param0;
 
@@ -208,7 +202,6 @@ struct MapNode
 
 private:
 	// Deprecated serialization methods
-	void serialize_pre22(u8 *dest, u8 version);
 	void deSerialize_pre22(u8 *source, u8 version);
 };
 
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index 47a29a6fc..e38061e30 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -377,18 +377,9 @@ public:
 		}
 	}
 	// CONTENT_IGNORE = not found
-	content_t getFreeId(bool require_full_param2)
+	content_t getFreeId()
 	{
-		// If allowed, first search in the large 4-bit-param2 pool
-		if(!require_full_param2){
-			for(u16 i=0x800; i<=0xfff; i++){
-				const ContentFeatures &f = m_content_features[i];
-				if(f.name == "")
-					return i;
-			}
-		}
-		// Then search from the small 8-bit-param2 pool
-		for(u16 i=0; i<=125; i++){
+		for(u32 i=0; i<=0xffff; i++){
 			const ContentFeatures &f = m_content_features[i];
 			if(f.name == "")
 				return i;
@@ -492,16 +483,8 @@ public:
 		u16 id = CONTENT_IGNORE;
 		bool found = m_name_id_mapping.getId(name, id);  // ignore aliases
 		if(!found){
-			// Determine if full param2 is required
-			bool require_full_param2 = (
-				def.param_type_2 == CPT2_FULL
-				||
-				def.param_type_2 == CPT2_FLOWINGLIQUID
-				||
-				def.legacy_wallmounted
-			);
 			// Get some id
-			id = getFreeId(require_full_param2);
+			id = getFreeId();
 			if(id == CONTENT_IGNORE)
 				return CONTENT_IGNORE;
 			if(name != "")
diff --git a/src/serialization.h b/src/serialization.h
index 266eada17..0d74ccf48 100644
--- a/src/serialization.h
+++ b/src/serialization.h
@@ -59,7 +59,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 	21: dynamic content type allocation
 	22: minerals removed, facedir & wallmounted changed
 	23: new node metadata format
-	24: NodeTimers
+	24: 16-bit node ids and node timers
 */
 // This represents an uninitialized or invalid format
 #define SER_FMT_VER_INVALID 255