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 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);
}
}
}
}
}