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 dungeons.rs
//! Port of `WorldGenDungeons`.
use common::JavaRandom;
use common::item::{Item, ItemStack};
use common::world::{Block, CHEST_SIZE, TileEntity};
use crate::level::Level;
const HEIGHT: i32 = 3;
/// A cobblestone room with a spawner and up to two chests, placed where its walls
/// have between one and five openings.
pub fn generate(level: &mut Level, [x, y, z]: [i32; 3], rand: &mut JavaRandom) {
let rx = rand.next_int(2) + 2;
let rz = rand.next_int(2) + 2;
let (min_x, max_x, min_z, max_z) = (x - rx - 1, x + rx + 1, z - rz - 1, z + rz + 1);
let mut openings = 0;
for cx in min_x..=max_x {
for cy in y - 1..=y + HEIGHT + 1 {
for cz in min_z..=max_z {
let solid = level.material(cx, cy, cz).is_solid();
if (cy == y - 1 || cy == y + HEIGHT + 1) && !solid {
return;
}
if (cx == min_x || cx == max_x || cz == min_z || cz == max_z)
&& cy == y
&& level.is_air(cx, cy, cz)
&& level.is_air(cx, cy + 1, cz)
{
openings += 1;
}
}
}
}
if !(1..=5).contains(&openings) {
return;
}
for cx in min_x..=max_x {
for cy in (y - 1..=y + HEIGHT).rev() {
for cz in min_z..=max_z {
let inside =
cx != min_x && cx != max_x && cz != min_z && cz != max_z && cy != y - 1;
if inside || (cy >= 0 && !level.material(cx, cy - 1, cz).is_solid()) {
level.set_block_notify(cx, cy, cz, Block::AIR);
} else if level.material(cx, cy, cz).is_solid() {
let wall = if cy == y - 1 && rand.next_int(4) != 0 {
Block::MOSSY_COBBLESTONE
} else {
Block::COBBLESTONE
};
level.set_block_notify(cx, cy, cz, wall);
}
}
}
}
'chests: for _ in 0..2 {
for _ in 0..3 {
let cx = x + rand.next_int(rx * 2 + 1) - rx;
let cz = z + rand.next_int(rz * 2 + 1) - rz;
if !level.is_air(cx, y, cz) {
continue;
}
let walls = [(-1, 0), (1, 0), (0, -1), (0, 1)]
.into_iter()
.filter(|&(dx, dz)| level.material(cx + dx, y, cz + dz).is_solid())
.count();
if walls == 1 {
level.set_block_notify(cx, y, cz, Block::CHEST);
for _ in 0..8 {
if let Some(stack) = loot(rand) {
let slot = rand.next_int(CHEST_SIZE as i32) as usize;
if let Some(TileEntity::Chest(items)) = level.tile_entity_mut(cx, y, cz) {
items[slot] = Some(stack);
}
}
}
continue 'chests;
}
}
}
level.set_block_notify(x, y, z, Block::SPAWNER);
let mob = match rand.next_int(4) {
0 => "Skeleton",
3 => "Spider",
_ => "Zombie",
};
if let Some(TileEntity::MobSpawner { entity_id, .. }) = level.tile_entity_mut(x, y, z) {
*entity_id = mob.into();
}
}
/// `pickCheckLootItem`.
fn loot(rand: &mut JavaRandom) -> Option<ItemStack> {
let stack = |item, rand: &mut JavaRandom| ItemStack::new(item, rand.next_int(4) + 1, 0);
Some(match rand.next_int(11) {
0 => ItemStack::one(Item::SADDLE),
1 => stack(Item::IRON_INGOT, rand),
2 => ItemStack::one(Item::BREAD),
3 => stack(Item::WHEAT, rand),
4 => stack(Item::GUNPOWDER, rand),
5 => stack(Item::STRING, rand),
6 => ItemStack::one(Item::BUCKET),
7 if rand.next_int(100) == 0 => ItemStack::one(Item::GOLDEN_APPLE),
8 if rand.next_int(2) == 0 => stack(Item::REDSTONE, rand),
9 if rand.next_int(10) == 0 => {
ItemStack::one(Item(Item::RECORD_13.0 + rand.next_int(2) as i16))
}
10 => ItemStack::new(Item::DYE, 1, 3),
_ => return None,
})
}