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 / server / src / blocks / plants.rs

//! Survival rules of `BlockFlower` and its subclasses, `BlockReed`, `BlockCactus` and `BlockSnow`.

use common::world::{Block, Material};

use super::{SIDES, break_block};
use crate::level::Level;

/// `canBlockStay` of the plants that break when their support goes away.
pub fn can_stay(level: &mut Level, block: Block, x: i32, y: i32, z: i32) -> bool {
    match block {
        Block::BROWN_MUSHROOM | Block::RED_MUSHROOM => {
            (0..128).contains(&y)
                && level.full_light(x, y, z) < 13
                && level.block(x, y - 1, z).is_opaque_cube()
        }
        Block::SUGAR_CANE => sugar_cane_can_stay(level, x, y, z),
        Block::CACTUS => cactus_can_stay(level, x, y, z),
        _ => {
            (level.full_light(x, y, z) >= 8 || level.sees_sky(x, y, z))
                && grows_on(block, level.block(x, y - 1, z))
        }
    }
}

/// `canPlaceBlockAt` of the plants: their support, with light only mattering later.
pub fn can_place(level: &mut Level, block: Block, x: i32, y: i32, z: i32) -> bool {
    match block {
        Block::BROWN_MUSHROOM | Block::RED_MUSHROOM => level.block(x, y - 1, z).is_opaque_cube(),
        Block::SUGAR_CANE | Block::CACTUS => can_stay(level, block, x, y, z),
        _ => grows_on(block, level.block(x, y - 1, z)),
    }
}

/// `BlockFlower.canThisPlantGrowOnThisBlockID`.
fn grows_on(plant: Block, soil: Block) -> bool {
    match plant {
        Block::DEAD_BUSH => soil == Block::SAND,
        Block::WHEAT => soil == Block::FARMLAND,
        _ => matches!(soil, Block::GRASS | Block::DIRT | Block::FARMLAND),
    }
}

/// `BlockReed.canPlaceBlockAt`: on sugar cane, or on grass or dirt next to water.
pub fn sugar_cane_can_stay(level: &mut Level, x: i32, y: i32, z: i32) -> bool {
    match level.block(x, y - 1, z) {
        Block::SUGAR_CANE => true,
        Block::GRASS | Block::DIRT => SIDES
            .into_iter()
            .any(|[dx, dz]| level.material(x + dx, y - 1, z + dz) == Material::Water),
        _ => false,
    }
}

/// `BlockCactus.canBlockStay`: no solid sides, standing on sand or cactus.
pub fn cactus_can_stay(level: &mut Level, x: i32, y: i32, z: i32) -> bool {
    SIDES
        .into_iter()
        .all(|[dx, dz]| !level.material(x + dx, y, z + dz).is_solid())
        && matches!(level.block(x, y - 1, z), Block::CACTUS | Block::SAND)
}

/// `BlockPumpkin.canPlaceBlockAt`.
pub fn pumpkin_can_place(level: &mut Level, x: i32, y: i32, z: i32) -> bool {
    let current = level.block(x, y, z);
    (current.is_air() || current.material().is_ground_cover()) && level.is_normal_cube(x, y - 1, z)
}

/// `BlockCake.onNeighborBlockChange`: cake without support vanishes, dropping nothing.
pub fn check_cake(level: &mut Level, x: i32, y: i32, z: i32) {
    if !cake_can_stay(level, x, y, z) {
        level.set_block_notify(x, y, z, Block::AIR);
    }
}

/// `checkFlowerChange` and its equivalents: breaks the plant if it can no longer stay.
pub fn check_stay(level: &mut Level, block: Block, x: i32, y: i32, z: i32) {
    if !can_stay(level, block, x, y, z) {
        break_block(level, block, x, y, z);
    }
}

/// `BlockSnow.canPlaceBlockAt`: snow needs an opaque, solid block below.
pub fn snow_fits(level: &mut Level, x: i32, y: i32, z: i32) -> bool {
    let below = level.block(x, y - 1, z);
    !below.is_air() && below.is_opaque_cube() && below.material().is_solid()
}

/// `BlockSnow.canSnowStay`.
pub fn check_snow(level: &mut Level, x: i32, y: i32, z: i32) {
    if !snow_fits(level, x, y, z) {
        break_block(level, Block::SNOW_LAYER, x, y, z);
    }
}

/// `BlockCake.canBlockStay`: on any solid material.
pub fn cake_can_stay(level: &mut Level, x: i32, y: i32, z: i32) -> bool {
    level.material(x, y - 1, z).is_solid()
}