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 common src map.rs
use crate::nbt::Compound;
use crate::world::Material;
pub const SIZE: usize = 128;
pub const PALETTE: [u32; 14] = [
0, 8368696, 16247203, 10987431, 16711680, 10526975, 10987431, 31744, 16777215, 10791096,
12020271, 7368816, 4210943, 6837042,
];
#[derive(Clone, Debug)]
pub struct Map {
pub center: [i32; 2],
pub dimension: i8,
pub scale: u8,
pub colors: Box<[u8; SIZE * SIZE]>,
pub icons: Vec<[i8; 3]>,
}
impl Map {
pub fn new(center: [i32; 2], dimension: i8) -> Self {
Self {
center,
dimension,
scale: 3,
colors: Box::new([0; SIZE * SIZE]),
icons: Vec::new(),
}
}
pub fn read(nbt: &Compound) -> Self {
let mut map = Self::new(
[nbt.int("xCenter"), nbt.int("zCenter")],
nbt.byte("dimension"),
);
map.scale = nbt.byte("scale").clamp(0, 4) as u8;
let width = i32::from(nbt.short("width"));
let height = i32::from(nbt.short("height"));
let bytes = nbt.byte_array("colors");
if width > 0 && height > 0 {
for y in ((height - 128) / 2).max(0)..height.min((height + 128) / 2) {
for x in ((width - 128) / 2).max(0)..width.min((width + 128) / 2) {
let tx = x + (128 - width) / 2;
let ty = y + (128 - height) / 2;
if (0..128).contains(&tx)
&& (0..128).contains(&ty)
&& let Some(&color) = bytes.get((x + y * width) as usize)
{
map.colors[(tx + ty * 128) as usize] = color;
}
}
}
}
map
}
pub fn write(&self, nbt: &mut Compound) {
nbt.set_int("xCenter", self.center[0]);
nbt.set_int("zCenter", self.center[1]);
nbt.set_byte("dimension", self.dimension);
nbt.set_byte("scale", self.scale as i8);
nbt.set_short("width", 128);
nbt.set_short("height", 128);
nbt.set_byte_array("colors", self.colors.to_vec());
}
pub fn receive(&mut self, data: &[u8]) -> bool {
match data {
[0, x, y, colors @ ..]
if !colors.is_empty() && *x < 128 && usize::from(*y) + colors.len() <= 128 =>
{
for (offset, &color) in colors.iter().enumerate() {
self.colors[usize::from(*x) + (usize::from(*y) + offset) * 128] = color;
}
true
}
[1, icons @ ..] if icons.len().is_multiple_of(3) => {
self.icons = icons
.as_chunks::<3>()
.0
.iter()
.map(|p| [p[0] as i8, p[1] as i8, p[2] as i8])
.collect();
true
}
_ => false,
}
}
pub fn rgba(&self) -> Vec<u8> {
self.colors
.iter()
.enumerate()
.flat_map(|(index, &color)| {
let Some(&rgb) = PALETTE
.get(usize::from(color / 4))
.filter(|_| color / 4 != 0)
else {
return [0, 0, 0, ((index + index / 128) & 1) as u8 * 8 + 16];
};
let shade = match color & 3 {
0 => 180,
2 => 255,
_ => 220,
};
[
((rgb >> 16 & 255) * shade / 255) as u8,
((rgb >> 8 & 255) * shade / 255) as u8,
((rgb & 255) * shade / 255) as u8,
255,
]
})
.collect()
}
}
pub fn material_color(material: Material) -> u8 {
match material {
Material::Grass => 1,
Material::Sand => 2,
Material::Cloth | Material::Sponge | Material::Web => 3,
Material::Lava | Material::Tnt => 4,
Material::Ice => 5,
Material::Iron => 6,
Material::Leaves | Material::Plants | Material::Cactus | Material::Pumpkin => 7,
Material::Snow | Material::BuiltSnow => 8,
Material::Clay => 9,
Material::Ground => 10,
Material::Rock | Material::Piston => 11,
Material::Water => 12,
Material::Wood => 13,
_ => 0,
}
}