Skip to content

Commit

Permalink
world: add sign position and material information to block entities
Browse files Browse the repository at this point in the history
  • Loading branch information
neocturne committed Dec 31, 2023
1 parent a1a9adb commit 145bee8
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 17 deletions.
7 changes: 6 additions & 1 deletion src/core/region_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,12 @@ impl<'a> SingleRegionProcessor<'a> {
}

if self.entities_needed {
let mut block_entities = chunk.block_entities();
let mut block_entities = chunk.block_entities().with_context(|| {
format!(
"Failed to process block entities for chunk {:?}",
chunk_coords,
)
})?;
self.entities.block_entities.append(&mut block_entities);
}

Expand Down
36 changes: 25 additions & 11 deletions src/world/block_entity.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Processing of block entity data
use minedmap_resource::{BlockFlag, BlockType};
use serde::{Deserialize, Serialize};

use super::{
Expand All @@ -11,17 +12,24 @@ use super::{
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(rename_all = "snake_case")]
pub enum SignKind {
/// Standing or attached sign
/// 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,
Expand All @@ -32,12 +40,13 @@ pub struct Sign {

impl Sign {
/// Processes a [de::BlockEntitySign] into a [Sign]
fn new(sign: &de::BlockEntitySign, kind: SignKind) -> 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,
}
Expand Down Expand Up @@ -68,16 +77,21 @@ pub struct BlockEntity {

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,
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,
Expand Down
57 changes: 52 additions & 5 deletions src/world/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ use anyhow::{bail, Context, Result};

use super::{block_entity::BlockEntity, de, section::*};
use crate::{
resource::{BiomeTypes, BlockTypes},
resource::{BiomeTypes, BlockType, BlockTypes},
types::*,
util::{self, ShiftMask},
};

/// Version-specific part of [Chunk]
Expand Down Expand Up @@ -274,12 +275,58 @@ impl<'a> Chunk<'a> {
}
}

/// Returns the section at a [SectionY] coordinate
fn section_at(&self, y: SectionY) -> Option<&dyn Section> {
match &self.inner {
ChunkInner::V1_18 { section_map } => section_map
.get(&y)
.map(|(section, _, _)| -> &dyn Section { section }),
ChunkInner::V1_13 { section_map, .. } => section_map
.get(&y)
.map(|(section, _)| -> &dyn Section { section }),
ChunkInner::V0 { section_map, .. } => section_map
.get(&y)
.map(|(section, _)| -> &dyn Section { section }),
ChunkInner::Empty => None,
}
}

/// Returns the [BlockType] at a given coordinate
fn block_type_at(&self, y: SectionY, coords: SectionBlockCoords) -> Result<Option<&BlockType>> {
let Some(section) = self.section_at(y) else {
return Ok(None);
};
section.block_at(coords)
}

/// Returns the [BlockType] at the coordinates of a [de::BlockEntity]
fn block_type_at_block_entity(
&self,
block_entity: &de::BlockEntity,
) -> Result<Option<&BlockType>> {
let x: BlockX = util::from_flat_coord(block_entity.x).2;
let z: BlockZ = util::from_flat_coord(block_entity.z).2;
let (section_y, block_y) = block_entity.y.shift_mask(BLOCK_BITS);

let coords = SectionBlockCoords {
xz: LayerBlockCoords { x, z },
y: BlockY::new(block_y),
};

self.block_type_at(SectionY(section_y), coords)
}

/// Processes all of the chunk's block entities
pub fn block_entities(&self) -> Vec<BlockEntity> {
self.block_entities
pub fn block_entities(&self) -> Result<Vec<BlockEntity>> {
let entities: Vec<Option<BlockEntity>> = self
.block_entities
.iter()
.filter_map(BlockEntity::new)
.collect()
.map(|block_entity| {
let block_type = self.block_type_at_block_entity(block_entity)?;
Ok(BlockEntity::new(block_entity, block_type))
})
.collect::<Result<_>>()?;
Ok(entities.into_iter().flatten().collect())
}
}

Expand Down

0 comments on commit 145bee8

Please sign in to comment.