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 protocol mod.rs
//! Protocol version 14 (b1.7.3): packets, their wire format and connections.
//!
//! The integrated server exchanges packets in memory; remote play uses the same packets over TCP.
mod packet;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;
use std::sync::mpsc::{self, Receiver, Sender, SyncSender, TryIter};
pub use packet::{Metadata, MetadataValue, Packet, ProtocolError};
pub const PROTOCOL_VERSION: i32 = 14;
/// One end of an in-memory packet stream.
pub struct Connection {
sender: Sender<Packet>,
receiver: Receiver<Packet>,
/// Terrain packets still waiting for a socket, which a server throttles on.
backlog: Option<Arc<AtomicUsize>>,
}
impl Connection {
/// Returns `false` once the other end has disconnected.
pub fn send(&self, packet: Packet) -> bool {
if let Some(backlog) = &self.backlog
&& matches!(packet, Packet::MapChunk { .. })
{
backlog.fetch_add(1, Relaxed);
}
self.sender.send(packet).is_ok()
}
/// `NetServerHandler.getNumChunkDataPackets`: unsent terrain on a socket connection.
pub fn terrain_backlog(&self) -> usize {
self.backlog.as_ref().map_or(0, |b| b.load(Relaxed))
}
pub fn receive(&self) -> TryIter<'_, Packet> {
self.receiver.try_iter()
}
/// Up to `limit` waiting packets, and whether the other end is gone with nothing left.
pub fn receive_some(&self, limit: usize) -> (Vec<Packet>, bool) {
let mut packets = Vec::new();
while packets.len() < limit {
match self.receiver.try_recv() {
Ok(packet) => packets.push(packet),
Err(mpsc::TryRecvError::Empty) => break,
Err(mpsc::TryRecvError::Disconnected) => return (packets, true),
}
}
(packets, false)
}
pub fn sender(&self) -> Sender<Packet> {
self.sender.clone()
}
}
/// `NetworkManager.processReadPackets`: the most packets handled per call.
pub const PACKETS_PER_TICK: usize = 101;
/// The socket side of a TCP connection. Received packets wait in a bounded queue, so a flood
/// stalls the socket reader instead of growing without limit.
pub struct Bridge {
pub incoming: SyncSender<Packet>,
pub outgoing: Receiver<Packet>,
backlog: Arc<AtomicUsize>,
}
impl Bridge {
/// Call once a packet from `outgoing` reached the socket.
pub fn written(&self, packet: &Packet) {
if matches!(packet, Packet::MapChunk { .. }) {
self.backlog.fetch_sub(1, Relaxed);
}
}
}
/// A connection fed by a socket through a [`Bridge`].
pub fn bridged_connection() -> (Bridge, Connection) {
let (incoming, receiver) = mpsc::sync_channel(4096);
let (sender, outgoing) = mpsc::channel();
let backlog = Arc::new(AtomicUsize::new(0));
(
Bridge {
incoming,
outgoing,
backlog: backlog.clone(),
},
Connection {
sender,
receiver,
backlog: Some(backlog),
},
)
}
/// Connects an integrated server to its client.
pub fn local_connection() -> (Connection, Connection) {
let (to_client, from_server) = mpsc::channel();
let (to_server, from_client) = mpsc::channel();
(
Connection {
sender: to_client,
receiver: from_client,
backlog: None,
},
Connection {
sender: to_server,
receiver: from_server,
backlog: None,
},
)
}