#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Aabb {
pub min_x: f64,
pub min_y: f64,
pub min_z: f64,
pub max_x: f64,
pub max_y: f64,
pub max_z: f64,
}
impl Aabb {
pub const FULL: Aabb = Aabb::new(0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
#[must_use]
pub const fn new(
min_x: f64,
min_y: f64,
min_z: f64,
max_x: f64,
max_y: f64,
max_z: f64,
) -> Self {
Aabb {
min_x,
min_y,
min_z,
max_x,
max_y,
max_z,
}
}
#[must_use]
pub fn at(&self, x: i32, y: i32, z: i32) -> Aabb {
let (x, y, z) = (f64::from(x), f64::from(y), f64::from(z));
Aabb::new(
self.min_x + x,
self.min_y + y,
self.min_z + z,
self.max_x + x,
self.max_y + y,
self.max_z + z,
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ShapeDependency {
None,
Neighbours(NeighbourShape),
EntityContext,
BlockEntity,
PositionOffset,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum NeighbourShape {
Fence,
Pane,
Wall,
Stairs,
Door,
Chest,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum WorldCoord {
Double,
Float {
int_offset: i8,
term: f32,
},
}
pub type WorldCoords = [WorldCoord; 6];
impl WorldCoord {
#[inline]
#[must_use]
pub fn apply(self, pos: i32, local: f64) -> f64 {
match self {
WorldCoord::Double => f64::from(pos) + local,
#[allow(clippy::cast_precision_loss)]
WorldCoord::Float { int_offset, term } => {
f64::from(pos.wrapping_add(i32::from(int_offset)) as f32 + term)
}
}
}
}
fn ordered(a: f64, b: f64) -> (f64, f64) {
if a <= b { (a, b) } else { (b, a) }
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Collision {
pub boxes: &'static [Aabb],
pub dependency: ShapeDependency,
pub world_coords: Option<&'static [WorldCoords]>,
}
impl Collision {
#[must_use]
pub fn uses_float_world_coords(&self) -> bool {
self.world_coords.is_some()
}
#[inline]
#[must_use]
pub fn world_box(&self, i: usize, x: i32, y: i32, z: i32) -> Aabb {
let b = &self.boxes[i];
match self.world_coords {
None => b.at(x, y, z),
Some(rules) => {
let r = &rules[i];
let (x0, x1) = ordered(r[0].apply(x, b.min_x), r[3].apply(x, b.max_x));
let (y0, y1) = ordered(r[1].apply(y, b.min_y), r[4].apply(y, b.max_y));
let (z0, z1) = ordered(r[2].apply(z, b.min_z), r[5].apply(z, b.max_z));
Aabb::new(x0, y0, z0, x1, y1, z1)
}
}
}
pub fn world_boxes(&self, x: i32, y: i32, z: i32) -> impl ExactSizeIterator<Item = Aabb> + '_ {
(0..self.boxes.len()).map(move |i| self.world_box(i, x, y, z))
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.boxes.is_empty() && self.dependency == ShapeDependency::None
}
#[must_use]
pub fn is_full_cube(&self) -> bool {
self.dependency == ShapeDependency::None && self.boxes == [Aabb::FULL]
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BoundingBox {
Empty,
Block,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum DigMaterial {
Rock,
Wood,
Plant,
Melon,
Leaves,
Dirt,
Web,
Wool,
Default,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Drop {
pub item: u16,
pub meta: Option<u8>,
pub min: u8,
pub max: u8,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
pub struct PhysicsFlags(pub u16);
impl PhysicsFlags {
pub const NONE: PhysicsFlags = PhysicsFlags(0);
pub const CLIMBABLE: PhysicsFlags = PhysicsFlags(1 << 0);
pub const WATER: PhysicsFlags = PhysicsFlags(1 << 1);
pub const LAVA: PhysicsFlags = PhysicsFlags(1 << 2);
pub const STUCK: PhysicsFlags = PhysicsFlags(1 << 3);
pub const SLIME: PhysicsFlags = PhysicsFlags(1 << 4);
pub const BED_BOUNCE: PhysicsFlags = PhysicsFlags(1 << 5);
pub const HONEY: PhysicsFlags = PhysicsFlags(1 << 6);
pub const BUBBLE_COLUMN: PhysicsFlags = PhysicsFlags(1 << 7);
pub const COLLIDE_SLOWDOWN: PhysicsFlags = PhysicsFlags(1 << 8);
pub const FENCE: PhysicsFlags = PhysicsFlags(1 << 9);
pub const WALL: PhysicsFlags = PhysicsFlags(1 << 10);
pub const FENCE_GATE: PhysicsFlags = PhysicsFlags(1 << 11);
pub const TRAPDOOR: PhysicsFlags = PhysicsFlags(1 << 12);
pub const SOUL_SPEED: PhysicsFlags = PhysicsFlags(1 << 13);
pub const FIRE: PhysicsFlags = PhysicsFlags(1 << 14);
#[must_use]
pub const fn contains(self, other: PhysicsFlags) -> bool {
self.0 & other.0 == other.0
}
#[must_use]
pub const fn union(self, other: PhysicsFlags) -> PhysicsFlags {
PhysicsFlags(self.0 | other.0)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct BlockPhysics {
pub slipperiness: f32,
pub speed_factor: f64,
pub jump_factor: f32,
pub stuck_multiplier: [f64; 3],
pub flags: PhysicsFlags,
}
impl BlockPhysics {
pub const DEFAULT: BlockPhysics = BlockPhysics {
slipperiness: 0.6,
speed_factor: 1.0,
jump_factor: 1.0,
stuck_multiplier: [1.0, 1.0, 1.0],
flags: PhysicsFlags::NONE,
};
#[allow(clippy::cast_possible_truncation)]
#[must_use]
pub const fn velocity_multiplier(&self) -> f32 {
self.speed_factor as f32
}
#[must_use]
pub const fn has(&self, flag: PhysicsFlags) -> bool {
self.flags.contains(flag)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct BlockInfo {
pub id: u16,
pub name: &'static str,
pub display_name: &'static str,
pub hardness: Option<f32>,
pub resistance: f32,
pub stack_size: u8,
pub diggable: bool,
pub transparent: bool,
pub emit_light: u8,
pub filter_light: u8,
pub bounding_box: BoundingBox,
pub material: Option<DigMaterial>,
pub harvest_tools: &'static [u16],
pub drops: &'static [Drop],
pub physics: BlockPhysics,
}
impl BlockInfo {
#[must_use]
pub fn requires_tool(&self) -> bool {
!self.harvest_tools.is_empty()
}
#[must_use]
pub fn can_harvest_with(&self, item: Option<u16>) -> bool {
self.harvest_tools.is_empty() || item.is_some_and(|i| self.harvest_tools.contains(&i))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FluidKind {
Water,
Lava,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Fluid {
pub kind: FluidKind,
pub level: u8,
}
impl Fluid {
#[must_use]
pub const fn amount(self) -> u8 {
if self.level == 0 || self.level >= 8 {
8
} else {
8 - self.level
}
}
#[must_use]
pub const fn falling(self) -> bool {
self.level >= 8
}
#[must_use]
pub fn height(self) -> f32 {
f32::from(self.amount()) / 9.0
}
#[must_use]
pub const fn still(self) -> bool {
self.level == 0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ItemInfo {
pub id: u16,
pub name: &'static str,
pub display_name: &'static str,
pub stack_size: u8,
pub max_durability: Option<u16>,
pub variations: &'static [(u8, &'static str)],
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum EntityKind {
Mob,
Object,
Other,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct EntityInfo {
pub id: u16,
pub name: &'static str,
pub display_name: &'static str,
pub kind: EntityKind,
pub category: &'static str,
pub width: Option<f32>,
pub height: Option<f32>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct EntityDimensions {
pub width: f32,
pub height: f32,
pub eye_height: f32,
}
impl EntityDimensions {
#[must_use]
pub fn bounding_box(&self, x: f64, y: f64, z: f64) -> Aabb {
let half = f64::from(self.width / 2.0);
Aabb::new(
x - half,
y,
z - half,
x + half,
y + f64::from(self.height),
z + half,
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum VariantApplied {
Spawn,
Metadata,
NextTick,
Input,
Server,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct EntityVariant {
pub name: &'static str,
pub dimensions: EntityDimensions,
pub applied: VariantApplied,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct VanillaEntitySize {
pub name: &'static str,
pub registry_id: i32,
pub spawn: &'static str,
pub object_types: &'static [(i32, i32)],
pub targeting_margin: f32,
pub fixed: bool,
pub registered: Option<(f32, f32)>,
pub variants: &'static [EntityVariant],
pub poses: &'static [(&'static str, EntityDimensions)],
}
impl VanillaEntitySize {
#[must_use]
pub fn variant(&self, name: &str) -> Option<&'static EntityVariant> {
self.variants.iter().find(|v| v.name == name)
}
#[must_use]
pub fn default_dimensions(&self) -> Option<EntityDimensions> {
self.variant("default").map(|v| v.dimensions)
}
#[must_use]
pub fn baby(&self) -> Option<EntityDimensions> {
self.variant("baby").map(|v| v.dimensions)
}
#[must_use]
pub fn pose(&self, name: &str) -> Option<EntityDimensions> {
self.poses.iter().find(|(n, _)| *n == name).map(|(_, d)| *d)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct BiomeInfo {
pub id: u16,
pub name: &'static str,
pub display_name: &'static str,
pub category: &'static str,
pub temperature: f32,
pub rainfall: f32,
pub precipitation: &'static str,
pub dimension: &'static str,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct EnchantCost {
pub a: i16,
pub b: i16,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct EnchantmentInfo {
pub id: u16,
pub name: &'static str,
pub display_name: &'static str,
pub max_level: u8,
pub min_cost: EnchantCost,
pub max_cost: EnchantCost,
pub exclude: &'static [&'static str],
pub category: &'static str,
pub weight: u8,
pub treasure_only: bool,
pub curse: bool,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FoodInfo {
pub item: u16,
pub name: &'static str,
pub food_points: u8,
pub saturation: f32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct EffectInfo {
pub id: u8,
pub name: &'static str,
pub display_name: &'static str,
pub good: bool,
}
#[cfg_attr(not(any(feature = "v1_8", feature = "v1_16_5")), allow(dead_code))]
pub(crate) fn lookup_name<T: Copy>(index: &[(&'static str, T)], name: &str) -> Option<T> {
index
.binary_search_by(|(n, _)| (*n).cmp(name))
.ok()
.map(|i| index[i].1)
}
#[cfg_attr(not(any(feature = "v1_8", feature = "v1_16_5")), allow(dead_code))]
pub(crate) fn lookup_id<T, K: Ord>(
items: &'static [T],
key: K,
f: impl Fn(&T) -> K,
) -> Option<&'static T> {
items
.binary_search_by(|x| f(x).cmp(&key))
.ok()
.map(|i| &items[i])
}
#[cfg_attr(not(any(feature = "v1_8", feature = "v1_16_5")), allow(dead_code))]
pub(crate) fn tool_multiplier(
table: &[(DigMaterial, &[(u16, f32)])],
material: DigMaterial,
tool: u16,
) -> f32 {
table
.iter()
.find(|(m, _)| *m == material)
.and_then(|(_, tools)| tools.iter().find(|(t, _)| *t == tool))
.map_or(1.0, |(_, x)| *x)
}