diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index c2822b31b5..4225344509 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -309,6 +309,20 @@ impl Block { Block::air(SpriteKind::Empty) } } + + #[inline] + pub fn from_u32(x: u32) -> Option { + let [bk, r, g, b] = x.to_le_bytes(); + Some(Self { + kind: BlockKind::from_u8(bk)?, + attr: [r, g, b], + }) + } + + #[inline] + pub fn to_u32(&self) -> u32 { + u32::from_le_bytes([self.kind as u8, self.attr[0], self.attr[1], self.attr[2]]) + } } #[cfg(test)] diff --git a/server/src/terrain_persistence.rs b/server/src/terrain_persistence.rs index d6b5a0d200..67769c1b1b 100644 --- a/server/src/terrain_persistence.rs +++ b/server/src/terrain_persistence.rs @@ -113,7 +113,11 @@ pub struct Chunk { impl Chunk { pub fn deserialize_from(reader: R) -> Option { // Attempt deserialization through various versions - if let Ok(data) = bincode::deserialize_from::<_, version::V2>(reader.clone()) + if let Ok(data) = bincode::deserialize_from::<_, version::V3>(reader.clone()) + .map_err(|err| { warn!("Error when loading V3: {:?}", err); err }) + { + Some(Chunk::from(data)) + } else if let Ok(data) = bincode::deserialize_from::<_, version::V2>(reader.clone()) .map_err(|err| { warn!("Error when loading V2: {:?}", err); err }) { Some(Chunk::from(data)) @@ -134,21 +138,29 @@ impl Chunk { } mod version { - pub type Current = V2; + pub type Current = V3; fn version_magic(n: u16) -> u64 { (n as u64) | (0x3352ACEEA789 << 16) } + fn version<'de, D: serde::Deserializer<'de>, const V: u16>(de: D) -> Result { + u64::deserialize(de).and_then(|x| if x == version_magic(V) { + Ok(x) + } else { + Err(serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(x), &"correct version")) + }) + } + use super::*; // Convert back to current impl From for Current { fn from(chunk: Chunk) -> Self { - Self { version: version_magic(2), blocks: chunk.blocks + Self { version: version_magic(3), blocks: chunk.blocks .into_iter() - .map(|(pos, b)| (pos.x as u8, pos.y as u8, pos.z as i16, b)) + .map(|(pos, b)| (pos.x as u8, pos.y as u8, pos.z as i16, b.to_u32())) .collect() } } } @@ -173,18 +185,26 @@ mod version { pub blocks: Vec<(u8, u8, i16, Block)>, } - fn version<'de, D: serde::Deserializer<'de>, const V: u16>(de: D) -> Result { - u64::deserialize(de).and_then(|x| if x == version_magic(V) { - Ok(x) - } else { - Err(serde::de::Error::invalid_value(serde::de::Unexpected::Unsigned(x), &"correct version")) - }) - } - impl From for Chunk { fn from(v2: V2) -> Self { Self { blocks: v2.blocks .into_iter() .map(|(x, y, z, b)| (Vec3::new(x as i32, y as i32, z as i32), b)) .collect() } } } + + // V2 + + #[derive(Serialize, Deserialize)] + pub struct V3 { + #[serde(deserialize_with = "version::<_, 3>")] + pub version: u64, + pub blocks: Vec<(u8, u8, i16, u32)>, + } + + impl From for Chunk { + fn from(v3: V3) -> Self { Self { blocks: v3.blocks + .into_iter() + .map(|(x, y, z, b)| (Vec3::new(x as i32, y as i32, z as i32), Block::from_u32(b).unwrap_or(Block::empty()))) + .collect() } } + } }