212 lines
7.7 KiB
Rust
212 lines
7.7 KiB
Rust
use crate::block::GetStateForNeighborUpdateArgs;
|
|
use crate::block::OnPlaceArgs;
|
|
use pumpkin_data::BlockDirection;
|
|
use pumpkin_data::BlockState;
|
|
use pumpkin_data::BlockStateId;
|
|
use pumpkin_data::block_properties::EastWall;
|
|
use pumpkin_data::block_properties::HorizontalFacing;
|
|
use pumpkin_data::block_properties::NorthWall;
|
|
use pumpkin_data::block_properties::SouthWall;
|
|
use pumpkin_data::block_properties::WestWall;
|
|
use pumpkin_data::tag::Taggable;
|
|
use pumpkin_data::{Block, tag};
|
|
use pumpkin_macros::pumpkin_block_from_tag;
|
|
use pumpkin_util::math::position::BlockPos;
|
|
|
|
use crate::block::BlockBehaviour;
|
|
use crate::world::World;
|
|
type FenceGateProperties = pumpkin_data::block_properties::OakFenceGateLikeProperties;
|
|
type FenceLikeProperties = pumpkin_data::block_properties::OakFenceLikeProperties;
|
|
type WallProperties = pumpkin_data::block_properties::ResinBrickWallLikeProperties;
|
|
|
|
#[pumpkin_block_from_tag("minecraft:walls")]
|
|
pub struct WallBlock;
|
|
|
|
impl BlockBehaviour for WallBlock {
|
|
fn on_place(&self, args: OnPlaceArgs<'_>) -> BlockStateId {
|
|
let mut wall_props = WallProperties::default(args.block);
|
|
wall_props.waterlogged = args.replacing.water_source();
|
|
|
|
compute_wall_state(wall_props, args.world, args.block, args.position)
|
|
}
|
|
|
|
fn get_state_for_neighbor_update(
|
|
&self,
|
|
args: GetStateForNeighborUpdateArgs<'_>,
|
|
) -> BlockStateId {
|
|
let wall_props = WallProperties::from_state_id(args.state_id);
|
|
compute_wall_state(wall_props, args.world, args.block, args.position)
|
|
}
|
|
}
|
|
|
|
pub fn compute_wall_state(
|
|
mut wall_props: WallProperties,
|
|
world: &World,
|
|
block: &Block,
|
|
block_pos: &BlockPos,
|
|
) -> BlockStateId {
|
|
let (block_above, block_above_state) = world.get_block_and_state(&block_pos.up());
|
|
|
|
for direction in HorizontalFacing::all() {
|
|
let other_block_pos = block_pos.offset(direction.to_offset());
|
|
let (other_block, other_block_state) = world.get_block_and_state(&other_block_pos);
|
|
|
|
let connected = is_connected(block, direction, other_block, other_block_state);
|
|
|
|
let shape = if connected {
|
|
let raise = if block_above_state.is_full_cube() {
|
|
true
|
|
} else if block_above.has_tag(&tag::Block::MINECRAFT_WALLS) {
|
|
let other_props = WallProperties::from_state_id(block_above_state.id);
|
|
match direction {
|
|
HorizontalFacing::North => other_props.north != NorthWall::None,
|
|
HorizontalFacing::South => other_props.south != SouthWall::None,
|
|
HorizontalFacing::East => other_props.east != EastWall::None,
|
|
HorizontalFacing::West => other_props.west != WestWall::None,
|
|
}
|
|
} else if block_above.has_tag(&tag::Block::C_GLASS_PANES)
|
|
|| block_above.has_tag(&tag::Block::MINECRAFT_FENCES)
|
|
|| block_above == &Block::IRON_BARS
|
|
{
|
|
let other_props = FenceLikeProperties::from_state_id(block_above_state.id);
|
|
match direction {
|
|
HorizontalFacing::North => other_props.north,
|
|
HorizontalFacing::South => other_props.south,
|
|
HorizontalFacing::East => other_props.east,
|
|
HorizontalFacing::West => other_props.west,
|
|
}
|
|
} else if block_above.has_tag(&tag::Block::MINECRAFT_FENCE_GATES) {
|
|
let other_props = FenceGateProperties::from_state_id(block_above_state.id);
|
|
// gate is perp to connected direction
|
|
let perpendicular_gate = direction == other_props.facing.rotate_clockwise()
|
|
|| direction == other_props.facing.rotate_counter_clockwise();
|
|
|
|
perpendicular_gate && !other_props.open
|
|
} else {
|
|
false
|
|
};
|
|
if raise {
|
|
WallShape::Tall
|
|
} else {
|
|
WallShape::Low
|
|
}
|
|
} else {
|
|
WallShape::None
|
|
};
|
|
|
|
match direction {
|
|
HorizontalFacing::North => wall_props.north = shape.into(),
|
|
HorizontalFacing::South => wall_props.south = shape.into(),
|
|
HorizontalFacing::East => wall_props.east = shape.into(),
|
|
HorizontalFacing::West => wall_props.west = shape.into(),
|
|
}
|
|
}
|
|
|
|
let connected_north_south = wall_props.north != NorthWall::None
|
|
&& wall_props.south != SouthWall::None
|
|
&& wall_props.east == EastWall::None
|
|
&& wall_props.west == WestWall::None;
|
|
let connected_east_west = wall_props.north == NorthWall::None
|
|
&& wall_props.south == SouthWall::None
|
|
&& wall_props.east != EastWall::None
|
|
&& wall_props.west != WestWall::None;
|
|
let cross = wall_props.north != NorthWall::None
|
|
&& wall_props.south != SouthWall::None
|
|
&& wall_props.east != EastWall::None
|
|
&& wall_props.west != WestWall::None;
|
|
|
|
wall_props.up = if !(cross || connected_north_south || connected_east_west) {
|
|
true
|
|
} else if block_above.has_tag(&tag::Block::MINECRAFT_WALLS) {
|
|
let other_props = WallProperties::from_state_id(block_above_state.id);
|
|
other_props.up
|
|
} else if block_above.has_tag(&tag::Block::MINECRAFT_FENCE_GATES) {
|
|
let other_props = FenceGateProperties::from_state_id(block_above_state.id);
|
|
if other_props.open {
|
|
false
|
|
} else {
|
|
match other_props.facing {
|
|
HorizontalFacing::East | HorizontalFacing::West => connected_east_west,
|
|
HorizontalFacing::South | HorizontalFacing::North => connected_north_south,
|
|
}
|
|
}
|
|
} else {
|
|
false
|
|
};
|
|
wall_props.to_state_id(block)
|
|
}
|
|
|
|
fn is_connected(
|
|
block: &Block,
|
|
direction: HorizontalFacing,
|
|
other_block: &Block,
|
|
other_block_state: &BlockState,
|
|
) -> bool {
|
|
let mut connected = other_block == block
|
|
|| (other_block_state.is_solid() && other_block_state.is_full_cube())
|
|
|| other_block_state.is_side_solid(BlockDirection::from_cardinal_direction(
|
|
direction.opposite(),
|
|
))
|
|
|| other_block.has_tag(&tag::Block::MINECRAFT_WALLS)
|
|
|| other_block == &Block::IRON_BARS
|
|
|| other_block.has_tag(&tag::Block::C_GLASS_PANES);
|
|
|
|
// fence gates do not pass is_side_solid check
|
|
if !connected && other_block.has_tag(&tag::Block::MINECRAFT_FENCE_GATES) {
|
|
let fence_props = FenceGateProperties::from_state_id(other_block_state.id);
|
|
if fence_props.facing == direction.rotate_clockwise()
|
|
|| fence_props.facing == direction.rotate_counter_clockwise()
|
|
{
|
|
connected = true;
|
|
}
|
|
}
|
|
connected
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
enum WallShape {
|
|
None,
|
|
Low,
|
|
Tall,
|
|
}
|
|
|
|
impl From<WallShape> for NorthWall {
|
|
fn from(value: WallShape) -> Self {
|
|
match value {
|
|
WallShape::None => Self::None,
|
|
WallShape::Low => Self::Low,
|
|
WallShape::Tall => Self::Tall,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<WallShape> for SouthWall {
|
|
fn from(value: WallShape) -> Self {
|
|
match value {
|
|
WallShape::None => Self::None,
|
|
WallShape::Low => Self::Low,
|
|
WallShape::Tall => Self::Tall,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<WallShape> for EastWall {
|
|
fn from(value: WallShape) -> Self {
|
|
match value {
|
|
WallShape::None => Self::None,
|
|
WallShape::Low => Self::Low,
|
|
WallShape::Tall => Self::Tall,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<WallShape> for WestWall {
|
|
fn from(value: WallShape) -> Self {
|
|
match value {
|
|
WallShape::None => Self::None,
|
|
WallShape::Low => Self::Low,
|
|
WallShape::Tall => Self::Tall,
|
|
}
|
|
}
|
|
}
|