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 level updates.rs
use common::protocol::Packet;
use common::world::chunk::{self, HEIGHT};
use common::world::{Chunk, ChunkPos};
/// Port of the change batching of `PlayerInstance`: up to ten distinct positions and their
/// bounding box. Ten or more changes resend the whole box instead.
#[derive(Clone, Copy, Default)]
pub struct BlockUpdates {
/// `x << 12 | z << 8 | y`, chunk-local.
positions: [u16; 10],
count: usize,
min: [u8; 3],
max: [u8; 3],
}
impl BlockUpdates {
/// `markBlockNeedsUpdate` with chunk-local coordinates.
pub fn mark(&mut self, x: u8, y: u8, z: u8) {
let p = [x, y, z];
if self.count == 0 {
self.min = p;
self.max = p;
}
for (axis, &v) in p.iter().enumerate() {
self.min[axis] = self.min[axis].min(v);
self.max[axis] = self.max[axis].max(v);
}
if self.count < self.positions.len() {
let packed = u16::from(x) << 12 | u16::from(z) << 8 | u16::from(y);
if !self.positions[..self.count].contains(&packed) {
self.positions[self.count] = packed;
self.count += 1;
}
}
}
/// The packets that bring a client up to date: one change, a batch, or the changed box.
pub fn packets(&self, chunk: &Chunk) -> Vec<Packet> {
let ChunkPos { x: cx, z: cz } = chunk.pos;
let entry = |packed: u16| {
let (x, z, y) = (
usize::from(packed >> 12),
usize::from(packed >> 8 & 15),
usize::from(packed & 255),
);
let index = chunk::index(x, y, z);
(
chunk.blocks().get(index).0,
chunk.metadata.get(index),
[x, y, z],
)
};
match self.count {
0 => Vec::new(),
1 => {
let (block, metadata, [x, y, z]) = entry(self.positions[0]);
vec![Packet::BlockChange {
x: cx * 16 + x as i32,
y: y as u8,
z: cz * 16 + z as i32,
block,
metadata,
}]
}
10 => {
let min_y = usize::from(self.min[1]) / 2 * 2;
let max_y = ((usize::from(self.max[1]) / 2 + 1) * 2).min(HEIGHT);
let xs = usize::from(self.min[0])..usize::from(self.max[0]) + 1;
let zs = usize::from(self.min[2])..usize::from(self.max[2]) + 1;
let mut data = Vec::new();
chunk.write_region(&mut data, xs.clone(), min_y..max_y, zs.clone());
vec![Packet::MapChunk {
x: cx * 16 + xs.start as i32,
y: min_y as i16,
z: cz * 16 + zs.start as i32,
size: [
(xs.len() - 1) as u8,
(max_y - min_y - 1) as u8,
(zs.len() - 1) as u8,
],
data: data.into(),
}]
}
count => vec![Packet::MultiBlockChange {
chunk_x: cx,
chunk_z: cz,
changes: self.positions[..count]
.iter()
.map(|&packed| {
let (block, metadata, _) = entry(packed);
(packed as i16, block, metadata)
})
.collect(),
}],
}
}
}