From 5f84ec8ed2c4701c24032bac0ee45175f2904ddc Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 2 Apr 2025 22:43:02 +0200 Subject: [PATCH] world/text_value: add support for new NBT text serialization Starting with DataVersion 4290, text is stored as NBT instead of JSON. The structure remains the same. --- src/world/block_entity.rs | 19 ++++++++++++++----- src/world/chunk.rs | 9 ++++++++- src/world/sign.rs | 4 ++-- src/world/text_value.rs | 14 +++++++++++--- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/world/block_entity.rs b/src/world/block_entity.rs index 6ad58a1..589a53c 100644 --- a/src/world/block_entity.rs +++ b/src/world/block_entity.rs @@ -41,10 +41,15 @@ pub struct Sign { impl Sign { /// Processes a [de::BlockEntitySign] into a [Sign] - fn new(sign: &de::BlockEntitySign, kind: SignKind, material: Option) -> Sign { + fn new( + sign: &de::BlockEntitySign, + kind: SignKind, + material: Option, + data_version: u32, + ) -> Sign { let (front_text, back_text) = sign.text(); - let front_text = front_text.decode(); - let back_text = back_text.decode(); + let front_text = front_text.decode(data_version); + let back_text = back_text.decode(data_version); Sign { kind, material, @@ -78,7 +83,11 @@ pub struct BlockEntity { impl BlockEntity { /// Processes a [de::BlockEntity] into a [BlockEntity] - pub fn new(entity: &de::BlockEntity, block_type: Option<&BlockType>) -> Option { + pub fn new( + entity: &de::BlockEntity, + block_type: Option<&BlockType>, + data_version: u32, + ) -> Option { let wall_sign = block_type .map(|block_type| block_type.block_color.is(BlockFlag::WallSign)) .unwrap_or_default(); @@ -92,7 +101,7 @@ impl BlockEntity { let material = block_type .as_ref() .and_then(|block_type| block_type.sign_material.as_ref()); - let data = BlockEntityData::Sign(Sign::new(sign, kind, material.cloned())); + let data = BlockEntityData::Sign(Sign::new(sign, kind, material.cloned(), data_version)); Some(BlockEntity { x: entity.x, diff --git a/src/world/chunk.rs b/src/world/chunk.rs index c4744d0..311fca8 100644 --- a/src/world/chunk.rs +++ b/src/world/chunk.rs @@ -58,6 +58,8 @@ pub struct Chunk<'a> { inner: ChunkInner<'a>, /// Unprocessed block entities block_entities: &'a Vec, + /// Chunk data version + data_version: u32, } impl<'a> Chunk<'a> { @@ -87,6 +89,7 @@ impl<'a> Chunk<'a> { Chunk { inner, block_entities, + data_version, }, has_unknown, )) @@ -292,7 +295,11 @@ impl<'a> Chunk<'a> { .iter() .map(|block_entity| { let block_type = self.block_type_at_block_entity(block_entity)?; - Ok(BlockEntity::new(block_entity, block_type)) + Ok(BlockEntity::new( + block_entity, + block_type, + self.data_version, + )) }) .collect::>()?; Ok(entities.into_iter().flatten().collect()) diff --git a/src/world/sign.rs b/src/world/sign.rs index c913b6f..8e4e670 100644 --- a/src/world/sign.rs +++ b/src/world/sign.rs @@ -49,7 +49,7 @@ static DYE_COLORS: phf::Map<&'static str, Color> = phf::phf_map! { impl RawSignText<'_> { /// Decodes the [RawSignText] into a [SignText] - pub fn decode(&self) -> SignText { + pub fn decode(&self, data_version: u32) -> SignText { let color = self .color .map(|c| DYE_COLORS.get(c).copied().unwrap_or(DEFAULT_COLOR)); @@ -60,7 +60,7 @@ impl RawSignText<'_> { SignText( self.messages .iter() - .map(|message| message.deserialize().linearize(&parent)) + .map(|message| message.deserialize(data_version).linearize(&parent)) .collect(), ) } diff --git a/src/world/text_value.rs b/src/world/text_value.rs index 336b1b1..75defc4 100644 --- a/src/world/text_value.rs +++ b/src/world/text_value.rs @@ -171,12 +171,20 @@ impl Default for DeserializedText { /// Minecraft raw text value #[derive(Debug, Deserialize)] -pub struct TextValue(pub String); +pub struct TextValue(pub fastnbt::Value); impl TextValue { /// Deserializes a [TextValue] into a [DeserializedText] - pub fn deserialize(&self) -> DeserializedText { - serde_json::from_str(&self.0).unwrap_or_default() + pub fn deserialize(&self, data_version: u32) -> DeserializedText { + if data_version < 4290 { + if let fastnbt::Value::String(json) = &self.0 { + if let Ok(content) = serde_json::from_str(json) { + return content; + } + } + } + + fastnbt::from_value(&self.0).unwrap_or_default() } }