//! Processing of block entity data use minedmap_resource::{BlockFlag, BlockType}; use serde::{Deserialize, Serialize}; use super::{ de, sign::{BlockEntitySignExt, SignText}, }; /// Kind of sign block #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] #[serde(rename_all = "snake_case")] pub enum SignKind { /// Standing sign Sign, /// Sign attached to wall WallSign, /// Hanging sign HangingSign, /// Hanging sign attached to wall HangingWallSign, } /// Processed sign data #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct Sign { /// The kind of the sign pub kind: SignKind, /// The material of the sign #[serde(skip_serializing_if = "Option::is_none", default)] pub material: Option, /// The sign's front text #[serde(skip_serializing_if = "SignText::is_empty", default)] pub front_text: SignText, /// The sign's back text #[serde(skip_serializing_if = "SignText::is_empty", default)] pub back_text: SignText, } impl Sign { /// Processes a [de::BlockEntitySign] into a [Sign] fn new(sign: &de::BlockEntitySign, kind: SignKind, material: Option) -> Sign { let (front_text, back_text) = sign.text(); let front_text = front_text.decode(); let back_text = back_text.decode(); Sign { kind, material, front_text, back_text, } } } /// Data for different kinds of [BlockEntity] #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] #[serde(tag = "type", rename_all = "snake_case")] pub enum BlockEntityData { /// A sign block Sign(Sign), } /// A processed block entity #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct BlockEntity { /// Global X coordinate pub x: i32, /// Global Y coordinate pub y: i32, /// Global Z coordinate pub z: i32, /// Entity data #[serde(flatten)] pub data: BlockEntityData, } impl BlockEntity { /// Processes a [de::BlockEntity] into a [BlockEntity] pub fn new(entity: &de::BlockEntity, block_type: Option<&BlockType>) -> Option { let wall_sign = block_type .map(|block_type| block_type.block_color.is(BlockFlag::WallSign)) .unwrap_or_default(); let (kind, sign) = match (&entity.data, wall_sign) { (de::BlockEntityData::Sign(sign), false) => (SignKind::Sign, sign), (de::BlockEntityData::Sign(sign), true) => (SignKind::WallSign, sign), (de::BlockEntityData::HangingSign(sign), false) => (SignKind::HangingSign, sign), (de::BlockEntityData::HangingSign(sign), true) => (SignKind::HangingWallSign, sign), (de::BlockEntityData::Other, _) => return None, }; 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())); Some(BlockEntity { x: entity.x, y: entity.y, z: entity.z, data, }) } }