Theme

alex/beta-minecraft-rust

Minecraft Beta 1.7.3 Rewrite

BRANCH main
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
Download file

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,
        },
    )
}