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 / spawn.rs

use common::entity::Entity;
use common::math::floor_f64;
use common::world::{Block, ChunkPos};

use crate::level::Level;

/// Port of `World.getInitialSpawnLocation`: walks randomly from the origin until the
/// surface is sand. The search loads and populates chunks on the way, like the original.
pub fn find(level: &mut Level) -> (i32, i32) {
    let (mut x, mut z) = (0, 0);
    while first_uncovered(level, x, z) != Block::SAND {
        x += level.rand.next_int(64) - level.rand.next_int(64);
        z += level.rand.next_int(64) - level.rand.next_int(64);
    }
    (x, z)
}

/// `Entity.preparePlayerToSpawn`: raises the player until nothing collides.
pub fn prepare_player(level: &mut Level, entity: &mut Entity) {
    while entity.pos.y > 0.0 {
        entity.set_position(entity.pos);
        let region = entity.bb;
        let (x0, x1) = (floor_f64(region.min.x) >> 4, floor_f64(region.max.x) >> 4);
        let (z0, z1) = (floor_f64(region.min.z) >> 4, floor_f64(region.max.z) >> 4);
        for cx in x0..=x1 {
            for cz in z0..=z1 {
                level.load_chunk(ChunkPos::new(cx, cz));
            }
        }
        if level.block_boxes(&region).is_empty() {
            break;
        }
        entity.pos.y += 1.0;
    }
    entity.motion = glam::DVec3::ZERO;
    entity.pitch = 0.0;
}

/// `World.setSpawnLocation`, before a singleplayer respawn: moves the spawn off columns
/// without ground.
pub fn repair(level: &mut Level, [mut x, mut y, mut z]: [i32; 3]) -> [i32; 3] {
    if y <= 0 {
        y = 64;
    }
    while first_uncovered(level, x, z) == Block::AIR {
        x += level.rand.next_int(8) - level.rand.next_int(8);
        z += level.rand.next_int(8) - level.rand.next_int(8);
    }
    [x, y, z]
}

/// The `EntityPlayerMP` constructor: somewhere in the 20 by 20 square around the spawn.
pub fn multiplayer(level: &mut Level, entity: &mut Entity, [mut x, mut y, mut z]: [i32; 3]) {
    if level.has_sky() {
        x += entity.rand.next_int(20) - 10;
        y = top_solid(level, x, z);
        z += entity.rand.next_int(20) - 10;
    }
    let pos = glam::DVec3::new(f64::from(x) + 0.5, f64::from(y), f64::from(z) + 0.5);
    entity.set_location_and_angles(pos, 0.0, 0.0);
}

/// `World.findTopSolidBlock` of the server: one above the highest solid block, or -1.
fn top_solid(level: &mut Level, x: i32, z: i32) -> i32 {
    (1..128)
        .rev()
        .find(|&y| level.block(x, y, z).material().is_solid())
        .map_or(-1, |y| y + 1)
}

/// `World.getFirstUncoveredBlock`.
fn first_uncovered(level: &mut Level, x: i32, z: i32) -> Block {
    let mut y = 63;
    while !level.is_air(x, y + 1, z) {
        y += 1;
    }
    level.block(x, y, z)
}