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 examples debug_world.rs
//! Writes a debug world into the client's saves folder: a flat platform at spawn with double
//! chests holding a full stack of every item and block variant.
//!
//! `cargo run --release -p server --example debug_world -- [--game-dir DIR] [--seed SEED]`
//!
//! The game directory defaults to the client's `~/.minecraft`.
use common::item::{Item, ItemStack};
use common::world::chunk;
use common::world::{Block, CHEST_SIZE, Chunk, ChunkPos, TileEntity};
use server::save::{WorldInfo, WorldSave};
use std::path::PathBuf;
const NAME: &str = "Debug World";
const GROUND: usize = 63;
/// The platform covers these chunks on both axes.
const CHUNKS: std::ops::RangeInclusive<i32> = -2..=1;
fn variants(item: Item) -> i32 {
match item.block() {
Some(Block::WOOL) => 16,
Some(Block::LOG | Block::LEAVES | Block::SAPLING | Block::TALL_GRASS) => 3,
Some(Block::SLAB) => 4,
_ if item == Item::DYE => 16,
_ if item == Item::COAL => 2,
_ => 1,
}
}
fn stacks() -> Vec<ItemStack> {
(1..=i16::MAX)
.map(Item)
.filter_map(|item| item.properties().map(|p| (item, p.max_stack)))
.flat_map(|(item, max)| {
(0..variants(item)).map(move |damage| ItemStack::new(item, i32::from(max), damage))
})
.collect()
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut game_dir = std::env::var_os("HOME")
.map_or_else(|| PathBuf::from("."), PathBuf::from)
.join(".minecraft");
let mut seed = 0;
let mut args = std::env::args().skip(1);
while let Some(arg) = args.next() {
let mut value = || args.next().ok_or(format!("missing value for {arg}"));
match arg.as_str() {
"--game-dir" => game_dir = PathBuf::from(value()?),
"--seed" => seed = value()?.parse()?,
_ => return Err("usage: debug_world [--game-dir DIR] [--seed SEED]".into()),
}
}
// `GuiCreateWorld`: a taken folder name gets dashes appended
let mut dir = game_dir.join("saves").join(NAME);
while dir.exists() {
dir.as_mut_os_string().push("-");
}
// Double chests along x at z = 0, 2, 4, ..., one block apart
let stacks = stacks();
let chests: Vec<_> = stacks
.chunks(CHEST_SIZE)
.zip(0..)
.map(|(items, i)| {
let (pair, half) = (i / 2, i % 2);
([(pair % 5) * 3 + half - 7, (pair / 5) * 2 - 6], items)
})
.collect();
let save = WorldSave::open(&dir)?;
for cx in CHUNKS {
for cz in CHUNKS {
let pos = ChunkPos::new(cx, cz);
let mut chunk = Chunk::new(pos, chunk::empty_blocks());
chunk.populated = true;
for x in 0..16 {
for z in 0..16 {
chunk.swap_block(x, 0, z, Block::BEDROCK);
for y in 1..GROUND - 3 {
chunk.swap_block(x, y, z, Block::STONE);
}
for y in GROUND - 3..GROUND {
chunk.swap_block(x, y, z, Block::DIRT);
}
chunk.swap_block(x, GROUND, z, Block::GRASS);
}
}
for &([x, z], items) in &chests {
if ChunkPos::containing(x, z) != pos {
continue;
}
let (x, y, z) = ((x & 15) as usize, GROUND + 1, (z & 15) as usize);
chunk.swap_block(x, y, z, Block::CHEST);
let slots = Box::new(std::array::from_fn(|i| items.get(i).copied()));
chunk
.tile_entities
.insert((x << 11 | z << 7 | y) as u16, TileEntity::Chest(slots));
}
chunk.generate_sky_light();
save.overworld.save(&chunk, &[], 0)?;
}
}
save.overworld.flush()?;
let mut info = WorldInfo::new(seed, NAME);
info.spawn = [0, GROUND as i32 + 1, 0];
save.save_info(&mut info)?;
println!("Wrote {} chests to {}", chests.len(), dir.display());
Ok(())
}