Theme

alex/beta-minecraft-rust

Minecraft Beta 1.7.3 Rewrite

BRANCH main
main
SNAPSHOT Draw terrain GPU-driven from packed per-section buffers with GPU occlusion culling, add a render distance slider (2-128) with a quad/disk shape, cut chunk bookkeeping at high render distances, and fix a light underflow at y=0
DOWNLOAD
Download file

root / crates / common / src / entity / vehicle.rs

use glam::{DVec3, IVec3};

use crate::math::floor_f64;
use crate::world::Block;
use crate::world::shape::BlockView;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum VehicleKind {
    Boat,
    Minecart,
    StorageCart,
    PoweredCart,
}

impl VehicleKind {
    pub fn size(self) -> [f32; 2] {
        if self == Self::Boat {
            [1.5, 0.6]
        } else {
            [0.98, 0.7]
        }
    }
    pub fn y_offset(self) -> f32 {
        self.size()[1] / 2.0
    }
    pub fn seat(self, position: DVec3, yaw: f32) -> DVec3 {
        if self == Self::Boat {
            let yaw = f64::from(yaw) * std::f64::consts::PI / 180.0;
            position + DVec3::new(yaw.cos() * 0.4, -f64::from(0.3_f32), yaw.sin() * 0.4)
        } else {
            position - DVec3::Y * f64::from(0.3_f32)
        }
    }
}

#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct VehiclePose {
    pub hit: i32,
    pub damage: i32,
    pub direction: i32,
}

pub const RAIL_ENDPOINTS: [[[i32; 3]; 2]; 10] = [
    [[0, 0, -1], [0, 0, 1]],
    [[-1, 0, 0], [1, 0, 0]],
    [[-1, -1, 0], [1, 0, 0]],
    [[-1, 0, 0], [1, -1, 0]],
    [[0, 0, -1], [0, -1, 1]],
    [[0, -1, -1], [0, 0, 1]],
    [[0, 0, 1], [1, 0, 0]],
    [[0, 0, 1], [-1, 0, 0]],
    [[0, 0, -1], [-1, 0, 0]],
    [[0, 0, -1], [1, 0, 0]],
];

pub fn rail_at(world: &impl BlockView, position: DVec3) -> Option<([i32; 3], u8)> {
    let [x, mut y, z] = position.to_array().map(floor_f64);
    if is_rail(world.block(x, y - 1, z)) {
        y -= 1;
    }
    let block = world.block(x, y, z);
    if !is_rail(block) {
        return None;
    }
    let mask = if block == Block::RAIL { 15 } else { 7 };
    let shape = world.metadata(x, y, z) & mask;
    (shape < 10).then_some(([x, y, z], shape))
}

pub fn is_rail(block: Block) -> bool {
    matches!(
        block,
        Block::RAIL | Block::POWERED_RAIL | Block::DETECTOR_RAIL
    )
}

pub fn rail_position(world: &impl BlockView, position: DVec3) -> Option<DVec3> {
    let ([x, y, z], shape) = rail_at(world, position)?;
    let endpoints = RAIL_ENDPOINTS[usize::from(shape)];
    let base = DVec3::new(f64::from(x) + 0.5, f64::from(y) + 0.5, f64::from(z) + 0.5);
    let a = base + DVec3::from_array(endpoints[0].map(f64::from)) * 0.5;
    let b = base + DVec3::from_array(endpoints[1].map(f64::from)) * 0.5;
    let direction = (b - a) * DVec3::new(1.0, 2.0, 1.0);
    let t = if direction.x == 0.0 {
        position.z - f64::from(z)
    } else if direction.z == 0.0 {
        position.x - f64::from(x)
    } else {
        ((position.x - a.x) * direction.x + (position.z - a.z) * direction.z) * 2.0
    };
    let mut result = a + direction * t;
    result.y += if direction.y < 0.0 {
        1.0
    } else if direction.y > 0.0 {
        0.5
    } else {
        0.0
    };
    Some(result)
}

pub fn rail_offset(world: &impl BlockView, position: DVec3, offset: f64) -> Option<DVec3> {
    let ([_, y, _], shape) = rail_at(world, position)?;
    let endpoints = RAIL_ENDPOINTS[usize::from(shape)];
    let direction = (IVec3::from(endpoints[1]) - IVec3::from(endpoints[0]))
        .as_dvec3()
        .with_y(0.0)
        .normalize();
    let mut shifted =
        position.with_y(f64::from(y + i32::from((2..=5).contains(&shape)))) + direction * offset;
    let [x, _, z] = position.to_array().map(floor_f64);
    for end in endpoints {
        if end[1] != 0 && floor_f64(shifted.x) - x == end[0] && floor_f64(shifted.z) - z == end[2] {
            shifted.y += f64::from(end[1]);
        }
    }
    rail_position(world, shifted)
}