world: process sign data, prepare for serialization

This commit is contained in:
Matthias Schiffer 2023-11-25 20:34:50 +01:00
parent 638d5046c9
commit f0e0db63d3
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
5 changed files with 130 additions and 11 deletions

89
src/world/block_entity.rs Normal file
View file

@ -0,0 +1,89 @@
//! Processing of block entity data
use serde::{Deserialize, Serialize};
use super::{
de,
sign::{BlockEntitySignExt, SignText},
};
/// Kind of sign block
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SignKind {
/// Standing or attached sign
Sign,
/// Hanging sign
HangingSign,
}
/// Processed sign data
#[derive(Debug, Serialize, Deserialize)]
pub struct Sign {
/// The kind of the sign
pub kind: SignKind,
/// 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) -> Sign {
let (front_text, back_text) = sign.text();
let front_text = front_text.decode();
let back_text = back_text.decode();
Sign {
kind,
front_text,
back_text,
}
}
}
/// Data for different kinds of [BlockEntity]
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum BlockEntityData {
/// A sign block
Sign(Sign),
}
/// A processed block entity
#[derive(Debug, Serialize, Deserialize)]
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) -> Option<Self> {
let data = match &entity.data {
de::BlockEntityData::Sign(sign) => {
BlockEntityData::Sign(Sign::new(sign, SignKind::Sign))
}
de::BlockEntityData::HangingSign(sign) => {
BlockEntityData::Sign(Sign::new(sign, SignKind::HangingSign))
}
de::BlockEntityData::Other => return None,
};
Some(BlockEntity {
x: entity.x,
y: entity.y,
z: entity.z,
data,
})
}
}

View file

@ -10,7 +10,7 @@ use std::{
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use super::{de, section::*}; use super::{block_entity::BlockEntity, de, section::*};
use crate::{ use crate::{
resource::{BiomeTypes, BlockTypes}, resource::{BiomeTypes, BlockTypes},
types::*, types::*,
@ -55,6 +55,8 @@ pub enum ChunkInner<'a> {
pub struct Chunk<'a> { pub struct Chunk<'a> {
/// Version-specific data /// Version-specific data
inner: ChunkInner<'a>, inner: ChunkInner<'a>,
/// Unprocessed block entities
block_entities: &'a Vec<de::BlockEntity>,
} }
impl<'a> Chunk<'a> { impl<'a> Chunk<'a> {
@ -66,17 +68,27 @@ impl<'a> Chunk<'a> {
) -> Result<(Self, bool)> { ) -> Result<(Self, bool)> {
let data_version = data.data_version.unwrap_or_default(); let data_version = data.data_version.unwrap_or_default();
let (inner, has_unknown) = match &data.chunk { let ((inner, has_unknown), block_entities) = match &data.chunk {
de::ChunkVariant::V1_18 { de::ChunkVariant::V1_18 {
sections, sections,
block_entities: _, block_entities,
} => Self::new_v1_18(data_version, sections, block_types, biome_types)?, } => (
de::ChunkVariant::V0 { level } => { Self::new_v1_18(data_version, sections, block_types, biome_types)?,
Self::new_v0(data_version, level, block_types, biome_types)? block_entities,
} ),
de::ChunkVariant::V0 { level } => (
Self::new_v0(data_version, level, block_types, biome_types)?,
&level.tile_entities,
),
}; };
Ok((Chunk { inner }, has_unknown)) Ok((
Chunk {
inner,
block_entities,
},
has_unknown,
))
} }
/// [Chunk::new] implementation for Minecraft v1.18+ chunks /// [Chunk::new] implementation for Minecraft v1.18+ chunks
@ -230,6 +242,14 @@ impl<'a> Chunk<'a> {
}, },
} }
} }
/// Processes all of the chunk's block entities
pub fn block_entities(&self) -> Vec<BlockEntity> {
self.block_entities
.iter()
.filter_map(BlockEntity::new)
.collect()
}
} }
/// Reference to block, biome and block light data of a section /// Reference to block, biome and block light data of a section

View file

@ -2,7 +2,7 @@
use std::{collections::VecDeque, sync::Arc}; use std::{collections::VecDeque, sync::Arc};
use serde::Deserialize; use serde::{Deserialize, Serialize};
/// A span of formatted text /// A span of formatted text
/// ///
@ -11,22 +11,28 @@ use serde::Deserialize;
/// is handled by [DeserializedText]. /// is handled by [DeserializedText].
/// ///
/// Formatting that is not set in a node is inherited from the parent. /// Formatting that is not set in a node is inherited from the parent.
#[derive(Debug, Deserialize, Default)] #[derive(Debug, Serialize, Deserialize, Default)]
pub struct FormattedText { pub struct FormattedText {
#[serde(default)] #[serde(default)]
/// Text content /// Text content
pub text: String, pub text: String,
/// Text color /// Text color
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<Arc<String>>, pub color: Option<Arc<String>>,
/// Bold formatting /// Bold formatting
#[serde(skip_serializing_if = "Option::is_none")]
pub bold: Option<bool>, pub bold: Option<bool>,
/// Italic formatting /// Italic formatting
#[serde(skip_serializing_if = "Option::is_none")]
pub italic: Option<bool>, pub italic: Option<bool>,
/// Underlines formatting /// Underlines formatting
#[serde(skip_serializing_if = "Option::is_none")]
pub underlined: Option<bool>, pub underlined: Option<bool>,
/// Strikethrough formatting /// Strikethrough formatting
#[serde(skip_serializing_if = "Option::is_none")]
pub strikethrough: Option<bool>, pub strikethrough: Option<bool>,
/// Obfuscated formatting /// Obfuscated formatting
#[serde(skip_serializing_if = "Option::is_none")]
pub obfuscated: Option<bool>, pub obfuscated: Option<bool>,
} }
@ -71,7 +77,7 @@ impl From<String> for FormattedTextTree {
} }
/// List of [FormattedText] /// List of [FormattedText]
#[derive(Debug)] #[derive(Debug, Serialize, Deserialize)]
pub struct FormattedTextList(pub Vec<FormattedText>); pub struct FormattedTextList(pub Vec<FormattedText>);
impl FormattedTextList { impl FormattedTextList {

View file

@ -1,5 +1,6 @@
//! Data structures describing Minecraft save data //! Data structures describing Minecraft save data
pub mod block_entity;
pub mod chunk; pub mod chunk;
pub mod de; pub mod de;
pub mod json_text; pub mod json_text;

View file

@ -2,6 +2,8 @@
use std::sync::Arc; use std::sync::Arc;
use serde::{Deserialize, Serialize};
use super::{ use super::{
de, de,
json_text::{FormattedText, FormattedTextList, JSONText}, json_text::{FormattedText, FormattedTextList, JSONText},
@ -77,6 +79,7 @@ impl BlockEntitySignExt for de::BlockEntitySign {
} }
} }
#[derive(Debug, Default, Serialize, Deserialize)]
/// Deserialized and linearized sign text /// Deserialized and linearized sign text
pub struct SignText(pub Vec<FormattedTextList>); pub struct SignText(pub Vec<FormattedTextList>);