(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
{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;
// 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
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)
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);
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);
/*
*/
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);
}
}
-
void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
{
if(!ser_ver_supported(version))
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;
Private methods
*/
- void serialize_pre22(std::ostream &os, u8 version, bool disk);
void deSerialize_pre22(std::istream &is, u8 version, bool disk);
/*
{
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)
{
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;
// 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
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;
}
}
/*
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)
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
- 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
{
/*
Main content
- 0x00-0x7f: Short content type
- 0x80-0xff: Long content type
*/
u16 param0;
private:
// Deprecated serialization methods
- void serialize_pre22(u8 *dest, u8 version);
void deSerialize_pre22(u8 *source, u8 version);
};
}
}
// 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;
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 != "")
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