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 / populate / plants.rs

//! Ports of `WorldGenFlowers`, `WorldGenTallGrass`, `WorldGenDeadBush`, `WorldGenReed`,
//! `WorldGenPumpkin` and `WorldGenCactus`.

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

use crate::blocks;
use crate::level::Level;

/// A random point up to 7 blocks away horizontally and 3 vertically, biased towards the origin.
fn scatter(rand: &mut JavaRandom, x: i32, y: i32, z: i32) -> (i32, i32, i32) {
    let x = x + rand.next_int(8) - rand.next_int(8);
    let y = y + rand.next_int(4) - rand.next_int(4);
    let z = z + rand.next_int(8) - rand.next_int(8);
    (x, y, z)
}

/// Lowers `y` to the first block that is neither air nor leaves.
fn ground(level: &mut Level, [x, mut y, z]: [i32; 3]) -> [i32; 3] {
    while matches!(level.block(x, y, z), Block::AIR | Block::LEAVES) && y > 0 {
        y -= 1;
    }
    [x, y, z]
}

/// Places `plant` (with `metadata`, if given) at `tries` scattered points where it can stay.
fn scatter_plant(
    level: &mut Level,
    [x, y, z]: [i32; 3],
    rand: &mut JavaRandom,
    tries: usize,
    plant: Block,
    metadata: Option<u8>,
) {
    for _ in 0..tries {
        let (px, py, pz) = scatter(rand, x, y, z);
        if level.is_air(px, py, pz) && blocks::can_stay(level, plant, px, py, pz) {
            level.change_block(px, py, pz, plant, metadata);
        }
    }
}

/// `WorldGenFlowers`, also used for mushrooms.
pub fn flowers(level: &mut Level, pos: [i32; 3], rand: &mut JavaRandom, plant: Block) {
    scatter_plant(level, pos, rand, 64, plant, None);
}

/// `WorldGenTallGrass`; `kind` is the tall grass metadata (1 grass, 2 fern).
pub fn tall_grass(level: &mut Level, pos: [i32; 3], rand: &mut JavaRandom, kind: u8) {
    let pos = ground(level, pos);
    scatter_plant(level, pos, rand, 128, Block::TALL_GRASS, Some(kind));
}

/// `WorldGenDeadBush`.
pub fn dead_bushes(level: &mut Level, pos: [i32; 3], rand: &mut JavaRandom) {
    let pos = ground(level, pos);
    scatter_plant(level, pos, rand, 4, Block::DEAD_BUSH, None);
}

/// `WorldGenReed`: columns of two to four sugar cane next to water.
pub fn sugar_cane(level: &mut Level, [x, y, z]: [i32; 3], rand: &mut JavaRandom) {
    for _ in 0..20 {
        let px = x + rand.next_int(4) - rand.next_int(4);
        let pz = z + rand.next_int(4) - rand.next_int(4);
        let near_water = level.is_air(px, y, pz)
            && [(-1, 0), (1, 0), (0, -1), (0, 1)]
                .into_iter()
                .any(|(dx, dz)| level.material(px + dx, y - 1, pz + dz) == Material::Water);
        if near_water {
            let bound = rand.next_int(3) + 1;
            let height = 2 + rand.next_int(bound);
            for dy in 0..height {
                if blocks::sugar_cane_can_stay(level, px, y + dy, pz) {
                    level.set_block(px, y + dy, pz, Block::SUGAR_CANE);
                }
            }
        }
    }
}

/// `WorldGenPumpkin`: pumpkins facing a random direction, on grass.
pub fn pumpkins(level: &mut Level, [x, y, z]: [i32; 3], rand: &mut JavaRandom) {
    for _ in 0..64 {
        let (px, py, pz) = scatter(rand, x, y, z);
        if level.is_air(px, py, pz)
            && level.block(px, py - 1, pz) == Block::GRASS
            && blocks::pumpkin_can_place(level, px, py, pz)
        {
            let facing = rand.next_int(4) as u8;
            level.set_block_with_metadata(px, py, pz, Block::PUMPKIN, facing);
        }
    }
}

/// `WorldGenCactus`: columns of one to three cacti.
pub fn cacti(level: &mut Level, [x, y, z]: [i32; 3], rand: &mut JavaRandom) {
    for _ in 0..10 {
        let (px, py, pz) = scatter(rand, x, y, z);
        if level.is_air(px, py, pz) {
            let bound = rand.next_int(3) + 1;
            let height = 1 + rand.next_int(bound);
            for dy in 0..height {
                if blocks::cactus_can_stay(level, px, py + dy, pz) {
                    level.set_block(px, py + dy, pz, Block::CACTUS);
                }
            }
        }
    }
}