use crate::common::{
Aabb, BiomeInfo, BlockInfo, BlockPhysics, Collision, DigMaterial, EffectInfo, EnchantmentInfo,
EntityInfo, EntityKind, Fluid, FluidKind, FoodInfo, ItemInfo, NeighbourShape, PhysicsFlags,
ShapeDependency, lookup_id, lookup_name,
};
use crate::generated::v1_12 as g;
pub const BLOCK_ID_SPACE: usize = 256;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum MaterialKind {
Air,
Water,
Lava,
Ice,
Other,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Material {
pub name: &'static str,
pub kind: MaterialKind,
pub blocks_movement: bool,
pub solid: bool,
pub liquid: bool,
pub opaque: bool,
pub replaceable: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct StateFlags(pub u8);
impl StateFlags {
pub const FULL_CUBE: StateFlags = StateFlags(1 << 0);
pub const NORMAL_CUBE: StateFlags = StateFlags(1 << 1);
pub const BLOCK_NORMAL_CUBE: StateFlags = StateFlags(1 << 2);
pub const TOP_SOLID: StateFlags = StateFlags(1 << 3);
pub const OPAQUE_CUBE: StateFlags = StateFlags(1 << 4);
pub const FULL_BLOCK: StateFlags = StateFlags(1 << 5);
pub const CAUSES_SUFFOCATION: StateFlags = StateFlags(1 << 6);
#[must_use]
pub const fn contains(self, other: StateFlags) -> bool {
self.0 & other.0 == other.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Face {
Down,
Up,
North,
South,
West,
East,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FaceShape {
Solid,
Bowl,
CenterSmall,
MiddlePoleThin,
Center,
MiddlePole,
CenterBig,
MiddlePoleThick,
Undefined,
}
const FACE_SHAPES: [FaceShape; 9] = [
FaceShape::Solid,
FaceShape::Bowl,
FaceShape::CenterSmall,
FaceShape::MiddlePoleThin,
FaceShape::Center,
FaceShape::MiddlePole,
FaceShape::CenterBig,
FaceShape::MiddlePoleThick,
FaceShape::Undefined,
];
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Selection {
pub bounds: Aabb,
pub dependency: ShapeDependency,
pub multi_pass_ray: bool,
pub can_collide: bool,
pub can_collide_liquid: bool,
pub has_collision_box: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Block(pub(crate) u8);
impl Block {
#[must_use]
pub fn from_id(id: u8) -> Option<Block> {
(g::blocks::BLOCK_SLOT[id as usize] != 255).then_some(Block(id))
}
#[must_use]
pub fn from_name(name: &str) -> Option<Block> {
lookup_name(&g::blocks::BLOCK_NAMES, name).map(Block)
}
#[must_use]
pub const fn id(self) -> u8 {
self.0
}
#[must_use]
pub fn info(self) -> &'static BlockInfo {
&g::blocks::BLOCKS[g::blocks::BLOCK_SLOT[self.0 as usize] as usize]
}
#[must_use]
pub fn name(self) -> &'static str {
self.info().name
}
#[must_use]
pub fn physics(self) -> &'static BlockPhysics {
&self.info().physics
}
#[must_use]
pub fn material(self) -> Material {
g::blocks::MATERIALS[g::blocks::BLOCK_MATERIAL[self.0 as usize] as usize]
}
#[must_use]
pub fn is_collidable(self) -> bool {
g::blocks::BLOCK_BITS[self.0 as usize] & 1 != 0
}
#[must_use]
pub fn fence_excluded(self) -> bool {
g::blocks::BLOCK_BITS[self.0 as usize] & 2 != 0
}
#[must_use]
pub fn wall_excluded(self) -> bool {
g::blocks::BLOCK_BITS[self.0 as usize] & 4 != 0
}
#[must_use]
pub fn pane_excluded(self) -> bool {
g::blocks::BLOCK_BITS[self.0 as usize] & 8 != 0
}
#[must_use]
pub fn shape_dependency(self) -> ShapeDependency {
g::blocks::BLOCK_SHAPE_DEPENDENCY[self.0 as usize]
}
#[must_use]
pub const fn with_meta(self, meta: u8) -> BlockState {
BlockState(((self.0 as u16) << 4) | (meta & 15) as u16)
}
#[must_use]
pub const fn default_state(self) -> BlockState {
self.with_meta(0)
}
pub fn all() -> impl Iterator<Item = Block> {
(0..=255u8).filter_map(Block::from_id)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct BlockState(u16);
impl BlockState {
pub const AIR: BlockState = BlockState(0);
#[must_use]
pub fn from_raw(raw: u16) -> Option<BlockState> {
(raw < 4096 && g::blocks::BLOCK_SLOT[(raw >> 4) as usize] != 255).then_some(BlockState(raw))
}
#[must_use]
pub fn from_raw_vanilla(raw: u16) -> BlockState {
match BlockState::from_raw(raw) {
Some(s) if s.is_registered() => s,
_ => BlockState::AIR,
}
}
#[must_use]
pub fn is_registered(self) -> bool {
g::blocks::REGISTERED_METAS[(self.0 >> 4) as usize] & (1 << (self.0 & 15)) != 0
}
#[must_use]
pub const fn new(block: Block, meta: u8) -> BlockState {
block.with_meta(meta)
}
#[must_use]
pub const fn raw(self) -> u16 {
self.0
}
#[must_use]
pub const fn block(self) -> Block {
Block((self.0 >> 4) as u8)
}
#[must_use]
pub const fn meta(self) -> u8 {
(self.0 & 15) as u8
}
#[must_use]
pub const fn is_air(self) -> bool {
self.0 >> 4 == 0
}
#[must_use]
pub fn collision(self) -> Collision {
Collision {
boxes: self.shape(),
dependency: g::blocks::BLOCK_SHAPE_DEPENDENCY[(self.0 >> 4) as usize],
world_coords: None,
}
}
#[must_use]
pub fn shape(self) -> &'static [Aabb] {
g::blocks::SHAPES[g::blocks::STATE_SHAPE[self.0 as usize] as usize]
}
#[must_use]
pub fn flags(self) -> StateFlags {
StateFlags(g::blocks::STATE_FLAGS[self.0 as usize])
}
#[must_use]
pub fn is_normal_cube(self) -> bool {
self.flags().contains(StateFlags::NORMAL_CUBE)
}
#[must_use]
pub fn is_full_cube(self) -> bool {
self.flags().contains(StateFlags::FULL_CUBE)
}
#[must_use]
pub fn face_shape(self, face: Face) -> FaceShape {
let v = g::blocks::STATE_FACES[self.0 as usize] >> (4 * face as u32);
FACE_SHAPES[(v & 15) as usize]
}
#[must_use]
pub fn selection(self) -> Selection {
let f = g::blocks::STATE_SELECTION_FLAGS[self.0 as usize];
let dependency = g::blocks::BLOCK_SHAPE_DEPENDENCY[(self.0 >> 4) as usize];
Selection {
bounds: g::blocks::SELECTION_BOUNDS
[g::blocks::STATE_SELECTION[self.0 as usize] as usize],
dependency,
multi_pass_ray: dependency == ShapeDependency::Neighbours(NeighbourShape::Stairs),
can_collide: f & 1 != 0,
can_collide_liquid: f & 2 != 0,
has_collision_box: f & 4 != 0,
}
}
#[must_use]
pub fn fluid(self) -> Option<Fluid> {
let flags = self.block().physics().flags;
let kind = if flags.contains(PhysicsFlags::WATER) {
FluidKind::Water
} else if flags.contains(PhysicsFlags::LAVA) {
FluidKind::Lava
} else {
return None;
};
Some(Fluid {
kind,
level: self.meta(),
})
}
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
pub fn slime_dimensions(n: i32) -> crate::common::EntityDimensions {
let s = 0.510_000_05_f32 * n as f32;
crate::common::EntityDimensions {
width: s,
height: s,
eye_height: 0.625 * s,
}
}
crate::macros::common_api!();