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 / common / src / world / fluid.rs

//! Fluid levels and currents of `BlockFluid`.

use glam::DVec3;

use super::Material;
use super::shape::BlockView;

/// `Vec3D.normalize`, with the length rounded to a float like `MathHelper.sqrt_double`.
pub fn normalize(v: DVec3) -> DVec3 {
    let length = f64::from(v.length() as f32);
    if length < 1.0e-4 {
        DVec3::ZERO
    } else {
        v / length
    }
}

/// The level of a fluid, with falling fluid counted as a source.
fn level(metadata: u8) -> u8 {
    if metadata >= 8 { 0 } else { metadata }
}

/// `BlockFluid.getPercentAir`.
pub fn percent_air(metadata: u8) -> f32 {
    f32::from(level(metadata) + 1) / 9.0
}

/// `getEffectiveFlowDecay`: the level, with falling fluid as a source, or -1 for other materials.
fn effective_decay(view: &impl BlockView, material: Material, x: i32, y: i32, z: i32) -> i32 {
    if view.block(x, y, z).material() != material {
        return -1;
    }
    i32::from(level(view.metadata(x, y, z)))
}

/// `BlockFluid.getFlowVector`: the normalized current at a fluid block.
pub fn flow_vector(view: &impl BlockView, material: Material, x: i32, y: i32, z: i32) -> DVec3 {
    let own = effective_decay(view, material, x, y, z);
    let mut flow = DVec3::ZERO;
    for (dx, dz) in [(-1, 0), (0, -1), (1, 0), (0, 1)] {
        let (nx, nz) = (x + dx, z + dz);
        let neighbor = effective_decay(view, material, nx, y, nz);
        let weight = if neighbor < 0 {
            if view.block(nx, y, nz).material().is_solid() {
                continue;
            }
            let below = effective_decay(view, material, nx, y - 1, nz);
            if below < 0 {
                continue;
            }
            below - (own - 8)
        } else {
            neighbor - own
        };
        flow += DVec3::new(f64::from(dx * weight), 0.0, f64::from(dz * weight));
    }
    if view.metadata(x, y, z) >= 8 {
        let solid = |x: i32, y: i32, z: i32| {
            let m = view.block(x, y, z).material();
            m != material && m != Material::Ice && m.is_solid()
        };
        let walled = [(0, -1), (0, 1), (-1, 0), (1, 0)]
            .into_iter()
            .any(|(dx, dz)| solid(x + dx, y, z + dz) || solid(x + dx, y + 1, z + dz));
        if walled {
            flow = normalize(flow) + DVec3::new(0.0, -6.0, 0.0);
        }
    }
    normalize(flow)
}