alex/beta-minecraft-rust
Minecraft Beta 1.7.3 Rewrite
BRANCH 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
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()
}