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