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 nether.rs
//! Port of `ChunkProviderHell`'s terrain: a netherrack cavern with a lava sea at 32.
use common::JavaRandom;
use common::noise::PerlinOctaves;
use common::world::chunk::{self, HEIGHT, VOLUME};
use common::world::{Block, ChunkPos};
use crate::caves::Caves;
use crate::terrain::{Density, chunk_random, interpolate, surface_noise};
const SURFACE: i32 = 64;
pub struct NetherGenerator {
pub(crate) seed: i64,
density: Density,
soul_sand_gravel: PerlinOctaves,
exclusivity: PerlinOctaves,
caves: Caves,
/// `hellRNG` after construction, which population uses until a chunk is generated.
pub(crate) initial_rng: JavaRandom,
}
impl NetherGenerator {
pub fn new(seed: i64) -> Self {
let mut random = JavaRandom::new(seed);
let density = Density::new(&mut random);
let soul_sand_gravel = PerlinOctaves::new(&mut random, 4);
let exclusivity = PerlinOctaves::new(&mut random, 4);
// The unused `netherNoiseGen6` and `netherNoiseGen7`
PerlinOctaves::new(&mut random, 10);
PerlinOctaves::new(&mut random, 16);
Self {
seed,
density,
soul_sand_gravel,
exclusivity,
caves: Caves { seed, nether: true },
initial_rng: random,
}
}
/// `provideChunk`; also returns `hellRNG` as generation left it, which population reuses.
pub fn generate(&self, pos: ChunkPos) -> (Box<[Block; VOLUME]>, Option<JavaRandom>) {
let mut random = chunk_random(pos);
let mut blocks = chunk::empty_blocks();
// `generateHeightMap`: a density closing off the floor and the ceiling. The original
// also samples a scale and depth noise here, but never uses them
const VERTICAL: f64 = 2053.236;
let falloff = std::array::from_fn(|y| {
let value = (y as f64 * std::f64::consts::PI * 6.0 / 17.0).cos() * 2.0;
let distance = 4.0 - y.min(16 - y) as f64;
if distance > 0.0 {
value - distance * distance * distance * 10.0
} else {
value
}
});
let density = self
.density
.field(pos, VERTICAL, VERTICAL / 60.0, |_| falloff);
interpolate(&density, &mut blocks, |_, y, _, d| {
if d > 0.0 {
Block::NETHERRACK
} else if y < 32 {
Block::LAVA
} else {
Block::AIR
}
});
self.replace_surface(pos, &mut random, &mut blocks);
self.caves.carve(pos, &mut blocks);
(blocks, Some(random))
}
/// `buildSurfaces`: bedrock, and soul sand and gravel around the old sea level.
fn replace_surface(
&self,
pos: ChunkPos,
random: &mut JavaRandom,
blocks: &mut [Block; VOLUME],
) {
let [soul_sand, gravel, exclusivity] =
surface_noise(&self.soul_sand_gravel, &self.exclusivity, pos);
for z in 0..16 {
for x in 0..16 {
let column = x * 16 + z;
let has_soul_sand = soul_sand[column] + random.next_double() * 0.2 > 0.0;
let has_gravel = gravel[column] + random.next_double() * 0.2 > 0.0;
let depth = (exclusivity[column] / 3.0 + 3.0 + random.next_double() * 0.25) as i32;
let mut remaining = -1;
let mut top = Block::NETHERRACK;
let mut filler = Block::NETHERRACK;
for y in (0..HEIGHT as i32).rev() {
let index = chunk::index(x, y as usize, z);
if y >= 127 - random.next_int(5) || y <= random.next_int(5) {
blocks[index] = Block::BEDROCK;
continue;
}
let current = blocks[index];
if current.is_air() {
remaining = -1;
} else if current == Block::NETHERRACK {
if remaining == -1 {
if depth <= 0 {
(top, filler) = (Block::AIR, Block::NETHERRACK);
} else if (SURFACE - 4..=SURFACE + 1).contains(&y) {
(top, filler) = (Block::NETHERRACK, Block::NETHERRACK);
if has_gravel {
top = Block::GRAVEL;
}
if has_soul_sand {
(top, filler) = (Block::SOUL_SAND, Block::SOUL_SAND);
}
}
if y < SURFACE && top.is_air() {
top = Block::LAVA;
}
remaining = depth;
blocks[index] = if y >= SURFACE - 1 { top } else { filler };
} else if remaining > 0 {
remaining -= 1;
blocks[index] = filler;
}
}
}
}
}
}
}