MinedMap/src/world/block_entity.rs

103 lines
2.8 KiB
Rust

//! 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<String>,
/// 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<String>) -> 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<Self> {
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,
})
}
}