Massive net refactoring, protocol now defined via macros!
* Fixed cli.yml, which was blatently broken previously. * Split PacketData into PacketReadable and PacketWritable, which allows implementing PacketWritable for un-owned types (for example, &str and &[u8]). * Added impl_packet_data_for_num! and impl_varnum! which makes defining packet serialization for the numbers very concise. * Added define_packet! macro which makes defining packets easy and much less tedious. * Added ProtocolState macro which encapsulates packet enums and packet ids into a single unit. * Added define_packet! macro which makes defining protocol states trivial (it's just a simple id/packet mapping). * Made packet serialization/deserialization part of PacketFormat, which massively simplifies the API. It took a while to get the hang of this all, but the more I use Rust, the more I love it.master
parent
0b5d3c026f
commit
cfc7bd6f46
|
@ -4,6 +4,10 @@ author: James Martin
|
|||
about: A Minecraft protocol-compatible server written in Rust.
|
||||
args:
|
||||
- host:
|
||||
long: host
|
||||
help: The IP address the server will use to listen for connections. Defaults to any address (`::`).
|
||||
takes_value: true
|
||||
- port:
|
||||
help: The port the server will accept connections from. Defaults to 25565.
|
||||
long: port
|
||||
help: The port the server will accept connections from. Defaults to 25565.
|
||||
takes_value: true
|
||||
|
|
69
src/main.rs
69
src/main.rs
|
@ -5,7 +5,6 @@ mod net;
|
|||
use crate::net::{Reader, Writer};
|
||||
use crate::net::chat::Chat;
|
||||
use crate::net::format::{PacketFormat, DefaultPacketFormat};
|
||||
use crate::net::serialize::VecPacketDeserializer;
|
||||
use tokio::io::{BufReader, BufWriter};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use std::io;
|
||||
|
@ -13,8 +12,10 @@ use std::net::IpAddr;
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
let yaml = clap::load_yaml!("cli.yml");
|
||||
let args = clap::App::from_yaml(yaml).get_matches();
|
||||
use clap::{App, load_yaml};
|
||||
|
||||
let yaml = load_yaml!("cli.yml");
|
||||
let args = App::from_yaml(yaml).get_matches();
|
||||
let host: IpAddr = args.value_of("host").unwrap_or("::").parse()
|
||||
.expect("Invalid host IP address.");
|
||||
let port: u16 = args.value_of("port").unwrap_or("25565").parse()
|
||||
|
@ -56,64 +57,52 @@ async fn accept_connection(mut socket: TcpStream) {
|
|||
|
||||
async fn interact_handshake<'a>(source: &mut Reader<'a>, dest: &mut Writer<'a>) -> io::Result<()> {
|
||||
use crate::net::packet::handshake::*;
|
||||
use PacketHandshakeServerbound::*;
|
||||
|
||||
let (id, data) = DefaultPacketFormat.recieve(source).await?;
|
||||
let mut deser = VecPacketDeserializer::new(&data);
|
||||
let pkt = DefaultPacketFormat.recieve::<HandshakeServerbound>(source).await?;
|
||||
|
||||
match read_packet_handshake(id, &mut deser)
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::Other, err)) {
|
||||
Ok(pkt) => match pkt {
|
||||
Handshake(pkt) => {
|
||||
if pkt.next_state == HandshakeNextState::Status {
|
||||
interact_status(source, dest).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "We do not support client log-in yet.".to_string()))
|
||||
}
|
||||
match pkt {
|
||||
HandshakeServerbound::Handshake(handshake) => {
|
||||
if handshake.next_state == HandshakeNextState::Status {
|
||||
interact_status(source, dest).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "We do not support client log-in yet.".to_string()))
|
||||
}
|
||||
},
|
||||
Err(err) => Err(io::Error::new(io::ErrorKind::Other, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn interact_status<'a>(source: &mut Reader<'a>, dest: &mut Writer<'a>) -> io::Result<()> {
|
||||
use crate::net::packet::status::*;
|
||||
use PacketStatusClientbound::*;
|
||||
use PacketStatusServerbound::*;
|
||||
|
||||
loop {
|
||||
let (id, data) = DefaultPacketFormat.recieve(source).await?;
|
||||
let mut deser = VecPacketDeserializer::new(&data);
|
||||
let pkt = DefaultPacketFormat.recieve::<StatusServerbound>(source).await?;
|
||||
|
||||
match read_packet_status(id, &mut deser)
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::Other, err)) {
|
||||
Ok(pkt) => match pkt {
|
||||
Request => {
|
||||
let mut buf = Vec::new();
|
||||
let id = write_packet_status(&mut buf, Response(PacketResponse {
|
||||
version: PacketResponseVersion {
|
||||
match pkt {
|
||||
StatusServerbound::Request(Request {}) => {
|
||||
DefaultPacketFormat.send(dest, &StatusClientbound::Response(Response {
|
||||
data: ResponseData {
|
||||
version: ResponseVersion {
|
||||
name: "1.16.1".to_string(),
|
||||
protocol: 736,
|
||||
},
|
||||
players: PacketResponsePlayers {
|
||||
players: ResponsePlayers {
|
||||
max: 255,
|
||||
online: 0,
|
||||
sample: Vec::new(),
|
||||
},
|
||||
description: Chat { text: "Hello, world!".to_string() },
|
||||
favicon: None,
|
||||
}));
|
||||
DefaultPacketFormat.send(dest, id, buf.as_slice()).await?;
|
||||
},
|
||||
Ping(payload) => {
|
||||
let mut buf = Vec::new();
|
||||
let id = write_packet_status(&mut buf, Pong(payload));
|
||||
DefaultPacketFormat.send(dest, id, buf.as_slice()).await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
})).await?;
|
||||
},
|
||||
StatusServerbound::Ping(ping) => {
|
||||
DefaultPacketFormat.send(dest, &StatusClientbound::Pong(Pong {
|
||||
payload: ping.payload
|
||||
})).await?;
|
||||
|
||||
// The status ping is now over so the server ends the connection.
|
||||
return Ok(());
|
||||
},
|
||||
Err(err) => return Err(io::Error::new(io::ErrorKind::Other, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use async_trait::async_trait;
|
||||
use crate::net::{Reader, Writer};
|
||||
use crate::net::state::ProtocolState;
|
||||
use std::boxed::Box;
|
||||
use std::io;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
#[async_trait]
|
||||
pub trait PacketFormat {
|
||||
async fn send<'wr, 'w>(&self, dest: &'wr mut Writer<'w>, packet_id: i32, data: &[u8]) -> io::Result<()>;
|
||||
async fn recieve<'rr, 'r>(&self, src: &'rr mut Reader<'r>) -> io::Result<(i32, Box<[u8]>)>;
|
||||
async fn send<'wr, 'w, P: ProtocolState + Sync>(&self, dest: &'wr mut Writer<'w>, pkt: &P) -> io::Result<()>;
|
||||
async fn recieve<'rr, 'r, P: ProtocolState>(&self, src: &'rr mut Reader<'r>) -> io::Result<P>;
|
||||
}
|
||||
|
||||
pub const MAX_CLIENT_PACKET_SIZE: usize = 32767;
|
||||
|
@ -34,9 +35,13 @@ async fn read_varint<'rr, 'r>(src: &'rr mut Reader<'r>) -> io::Result<(usize, i3
|
|||
|
||||
#[async_trait]
|
||||
impl PacketFormat for DefaultPacketFormat {
|
||||
async fn send<'wr, 'w>(&self, dest: &'wr mut Writer<'w>, packet_id: i32, data: &[u8]) -> io::Result<()> {
|
||||
async fn send<'wr, 'w, P: ProtocolState + Sync>(&self, dest: &'wr mut Writer<'w>, pkt: &P) -> io::Result<()> {
|
||||
use crate::net::serialize::{PacketSerializer, VarInt};
|
||||
|
||||
let packet_id = pkt.id();
|
||||
let mut data = Vec::new();
|
||||
pkt.write(&mut data);
|
||||
|
||||
let mut packet_id_buf = Vec::with_capacity(5);
|
||||
packet_id_buf.write(VarInt(packet_id));
|
||||
|
||||
|
@ -49,14 +54,16 @@ impl PacketFormat for DefaultPacketFormat {
|
|||
|
||||
dest.write(packet_length_buf.as_slice()).await?;
|
||||
dest.write(packet_id_buf.as_slice()).await?;
|
||||
dest.write(data).await?;
|
||||
dest.write(data.as_slice()).await?;
|
||||
dest.flush().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn recieve<'rr, 'r>(&self, src: &'rr mut Reader<'r>) -> io::Result<(i32, Box<[u8]>)> {
|
||||
async fn recieve<'rr, 'r, P: ProtocolState>(&self, src: &'rr mut Reader<'r>) -> io::Result<P> {
|
||||
use crate::net::serialize::VecPacketDeserializer;
|
||||
|
||||
let (_, length) = read_varint(src).await?;
|
||||
if length > MAX_CLIENT_PACKET_SIZE as i32 {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, "Packet was too long."));
|
||||
|
@ -69,6 +76,7 @@ impl PacketFormat for DefaultPacketFormat {
|
|||
buf.resize(length - id_length, 0);
|
||||
src.read_exact(buf.as_mut_slice()).await?;
|
||||
|
||||
Ok((id, buf.into_boxed_slice()))
|
||||
P::read(id, &mut VecPacketDeserializer::new(&buf))
|
||||
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ pub mod chat;
|
|||
pub mod format;
|
||||
pub mod packet;
|
||||
pub mod serialize;
|
||||
pub mod state;
|
||||
|
||||
use tokio::io::{BufReader, BufWriter};
|
||||
use tokio::net::tcp::{ReadHalf, WriteHalf};
|
||||
|
|
|
@ -1,2 +1,38 @@
|
|||
pub mod handshake;
|
||||
pub mod status;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! define_packets {
|
||||
{ $( packet $name:ident { $( $field:ident : $type:ty ),* } )+ } => {
|
||||
$(
|
||||
pub struct $name {
|
||||
$(
|
||||
pub $field: $type,
|
||||
)*
|
||||
}
|
||||
|
||||
impl crate::net::serialize::PacketReadable for $name {
|
||||
fn read(deser: &mut impl crate::net::serialize::PacketDeserializer) -> Result<Self, String> {
|
||||
$(
|
||||
let $field = deser.read::<$type>()?;
|
||||
)*
|
||||
deser.read_eof()?;
|
||||
Ok($name {
|
||||
$(
|
||||
$field: $field,
|
||||
)*
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::net::serialize::PacketWritable for &$name {
|
||||
fn write(self, ser: &mut impl crate::net::serialize::PacketSerializer) {
|
||||
$(
|
||||
self.$field.write(ser);
|
||||
)*
|
||||
ser.write_eof();
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,56 +1,48 @@
|
|||
use crate::net::serialize::{PacketData, PacketDeserializer, PacketSerializer, VarInt};
|
||||
use crate::{define_packets, define_states};
|
||||
use crate::net::serialize::{PacketReadable, PacketWritable, PacketDeserializer, PacketSerializer, VarInt};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum HandshakeNextState {
|
||||
Status,
|
||||
Login,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PacketHandshake {
|
||||
pub protocol_version: i32,
|
||||
pub server_address: String,
|
||||
pub server_port: u16,
|
||||
pub next_state: HandshakeNextState,
|
||||
}
|
||||
|
||||
impl PacketData for PacketHandshake {
|
||||
impl PacketReadable for HandshakeNextState {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let protocol_version = deser.read::<VarInt>()?.into();
|
||||
let server_address = deser.read::<String>()?;
|
||||
let server_port = deser.read::<u16>()?;
|
||||
let next_state = match deser.read::<VarInt>()?.into() {
|
||||
1 => HandshakeNextState::Status,
|
||||
2 => HandshakeNextState::Login,
|
||||
use HandshakeNextState::*;
|
||||
|
||||
Ok(match deser.read::<VarInt>()?.into() {
|
||||
1 => Status,
|
||||
2 => Login,
|
||||
n => return Err(format!("Invalid next protocol state in handshake: {}", n))
|
||||
};
|
||||
deser.read_eof()?;
|
||||
Ok(PacketHandshake {
|
||||
protocol_version: protocol_version,
|
||||
server_address: server_address,
|
||||
server_port: server_port,
|
||||
next_state: next_state,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.protocol_version);
|
||||
ser.write(self.server_address.clone());
|
||||
ser.write(self.server_port);
|
||||
impl PacketWritable for &HandshakeNextState {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
use HandshakeNextState::*;
|
||||
|
||||
ser.write(VarInt(match self {
|
||||
Status => 1,
|
||||
Login => 2,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PacketHandshakeServerbound {
|
||||
Handshake(PacketHandshake),
|
||||
}
|
||||
|
||||
pub fn read_packet_handshake(id: i32, deser: &mut impl PacketDeserializer)
|
||||
-> Result<PacketHandshakeServerbound, String> {
|
||||
use PacketHandshakeServerbound::*;
|
||||
|
||||
match id {
|
||||
0x00 => deser.read().map(Handshake),
|
||||
id => Err(format!("Invalid handshake packet id: {}", id))
|
||||
define_packets! {
|
||||
packet Handshake {
|
||||
protocol_version: VarInt,
|
||||
server_address: String,
|
||||
server_port: u16,
|
||||
next_state: HandshakeNextState
|
||||
}
|
||||
}
|
||||
|
||||
define_states! {
|
||||
state HandshakeClientbound { }
|
||||
|
||||
state HandshakeServerbound {
|
||||
0x00 => Handshake
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,81 +1,69 @@
|
|||
use crate::{define_packets, define_states};
|
||||
use crate::net::chat::Chat;
|
||||
use crate::net::serialize::{PacketDeserializer, PacketSerializer, PacketJson};
|
||||
use crate::net::serialize::{PacketJson};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct PacketResponseVersion {
|
||||
pub struct ResponseVersion {
|
||||
pub name: String,
|
||||
pub protocol: u32,
|
||||
}
|
||||
impl PacketJson for PacketResponseVersion {}
|
||||
impl PacketJson for ResponseVersion {}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct PacketResponsePlayersSample {
|
||||
pub struct ResponsePlayersSample {
|
||||
pub name: String,
|
||||
pub id: Uuid,
|
||||
}
|
||||
impl PacketJson for PacketResponsePlayersSample {}
|
||||
impl PacketJson for ResponsePlayersSample {}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct PacketResponsePlayers {
|
||||
pub struct ResponsePlayers {
|
||||
pub max: u32,
|
||||
pub online: u32,
|
||||
pub sample: Vec<PacketResponsePlayersSample>
|
||||
pub sample: Vec<ResponsePlayersSample>
|
||||
}
|
||||
impl PacketJson for PacketResponsePlayers {}
|
||||
impl PacketJson for ResponsePlayers {}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct PacketResponse {
|
||||
pub version: PacketResponseVersion,
|
||||
pub players: PacketResponsePlayers,
|
||||
pub struct ResponseData {
|
||||
pub version: ResponseVersion,
|
||||
pub players: ResponsePlayers,
|
||||
pub description: Chat,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub favicon: Option<String>,
|
||||
}
|
||||
impl PacketJson for PacketResponse {}
|
||||
impl PacketJson for ResponseData {}
|
||||
|
||||
pub enum PacketStatusClientbound {
|
||||
Response(PacketResponse),
|
||||
Pong([u8; 8]),
|
||||
}
|
||||
define_packets! {
|
||||
// Clientbound
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PacketStatusServerbound {
|
||||
Request,
|
||||
Ping([u8; 8]),
|
||||
}
|
||||
packet Response {
|
||||
data: ResponseData
|
||||
}
|
||||
|
||||
pub fn read_packet_status(id: i32, deser: &mut impl PacketDeserializer)
|
||||
-> Result<PacketStatusServerbound, String> {
|
||||
use PacketStatusServerbound::*;
|
||||
packet Pong {
|
||||
payload: [u8; 8]
|
||||
}
|
||||
|
||||
match id {
|
||||
0 => {
|
||||
deser.read_eof()?;
|
||||
Ok(Request)
|
||||
},
|
||||
1 => {
|
||||
let payload = deser.read::<[u8; 8]>()?;
|
||||
deser.read_eof()?;
|
||||
Ok(Ping(payload))
|
||||
}
|
||||
id => Err(format!("Invalid status packet id: {}", id))
|
||||
// Serverbound
|
||||
|
||||
packet Request { }
|
||||
|
||||
packet Ping {
|
||||
payload: [u8; 8]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_packet_status(ser: &mut impl PacketSerializer, packet: PacketStatusClientbound)
|
||||
-> i32 {
|
||||
use PacketStatusClientbound::*;
|
||||
define_states! {
|
||||
state StatusClientbound {
|
||||
0x00 => Response,
|
||||
0x01 => Pong
|
||||
}
|
||||
|
||||
match packet {
|
||||
Response(response) => {
|
||||
ser.write(response);
|
||||
0x00
|
||||
},
|
||||
Pong(payload) => {
|
||||
ser.write(payload);
|
||||
0x01
|
||||
}
|
||||
state StatusServerbound {
|
||||
0x00 => Request,
|
||||
0x01 => Ping
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,283 +1,15 @@
|
|||
use crate::net::format::MAX_CLIENT_PACKET_SIZE;
|
||||
use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::borrow::Borrow;
|
||||
use std::convert::{From, Into};
|
||||
|
||||
pub trait PacketData: Sized {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String>
|
||||
where Self: std::marker::Sized;
|
||||
fn write(&self, ser: &mut impl PacketSerializer);
|
||||
}
|
||||
|
||||
impl<const N: usize> PacketData for [u8; N] {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
use std::convert::TryInto;
|
||||
|
||||
let mut buf = [0; N];
|
||||
deser.read_exact(&mut buf)?;
|
||||
Ok(buf.try_into().unwrap())
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write_exact(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for bool {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let value = deser.read::<u8>()?;
|
||||
match value {
|
||||
0x00 => Ok(false),
|
||||
0x01 => Ok(true),
|
||||
n => Err(format!("{:0X} is not a valid boolean.", n))
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(*self as u8);
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for u8 {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<[u8; 1]>().map(u8::from_be_bytes)
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for i8 {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<[u8; 1]>().map(i8::from_be_bytes)
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for u16 {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<[u8; 2]>().map(u16::from_be_bytes)
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.to_be_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for i16 {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<[u8; 2]>().map(i16::from_be_bytes)
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.to_be_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for i32 {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<[u8; 4]>().map(i32::from_be_bytes)
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.to_be_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for i64 {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<[u8; 8]>().map(i64::from_be_bytes)
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.to_be_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for f32 {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<[u8; 4]>().map(f32::from_be_bytes)
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.to_be_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for f64 {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<[u8; 8]>().map(f64::from_be_bytes)
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.to_be_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VarInt(pub i32);
|
||||
|
||||
impl From<i32> for VarInt {
|
||||
fn from(x: i32) -> Self { VarInt(x) }
|
||||
}
|
||||
|
||||
impl Into<i32> for VarInt {
|
||||
fn into(self) -> i32 { self.0 }
|
||||
}
|
||||
|
||||
impl PacketData for VarInt {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let mut length = 1;
|
||||
let mut acc = 0;
|
||||
// VarInts must not be longer than 5 bytes.
|
||||
while length <= 5 {
|
||||
// If the highest bit is set, there are further bytes to be read from this VarInt;
|
||||
// the rest of the bits are the actual data in the VarInt.
|
||||
let read = deser.read::<u8>()?;
|
||||
acc |= (read & 0b01111111) as i32;
|
||||
|
||||
// There are no more bytes.
|
||||
if (read & 0b10000000) == 0 {
|
||||
return Ok(VarInt(acc));
|
||||
}
|
||||
|
||||
// Make space for the rest of the bits.
|
||||
acc = acc << 7;
|
||||
length += 1;
|
||||
}
|
||||
|
||||
// The VarInt was too long!
|
||||
Err("VarInt was more than 5 bytes.".to_string())
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
let mut value = self.0;
|
||||
loop {
|
||||
let mut temp = (value & 0b01111111) as u8;
|
||||
value = value >> 7;
|
||||
if value != 0 {
|
||||
temp |= 0b10000000;
|
||||
}
|
||||
ser.write(temp);
|
||||
|
||||
if value == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VarLong(pub i64);
|
||||
|
||||
impl From<i64> for VarLong {
|
||||
fn from(x: i64) -> Self { VarLong(x) }
|
||||
}
|
||||
|
||||
impl Into<i64> for VarLong {
|
||||
fn into(self) -> i64 { self.0 }
|
||||
}
|
||||
|
||||
impl PacketData for VarLong {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let mut length = 1;
|
||||
let mut acc = 0;
|
||||
// VarLongs must not be longer than 5 bytes.
|
||||
while length <= 10 {
|
||||
// If the highest bit is set, there are further bytes to be read from this VarLong;
|
||||
// the rest of the bits are the actual data in the VarLong.
|
||||
let read = deser.read::<u8>()?;
|
||||
acc |= (read & 0b01111111) as i64;
|
||||
|
||||
// There are no more bytes.
|
||||
if (read & 0b10000000) == 0 {
|
||||
return Ok(VarLong(acc));
|
||||
}
|
||||
|
||||
// Make space for the rest of the bits.
|
||||
acc = acc << 7;
|
||||
length += 1;
|
||||
}
|
||||
|
||||
// The VarLong was too long!
|
||||
Err("VarLong was more than 10 bytes.".to_string())
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
let mut value = self.0;
|
||||
loop {
|
||||
let mut temp = (value & 0b01111111) as u8;
|
||||
value = value >> 7;
|
||||
if value != 0 {
|
||||
temp |= 0b10000000;
|
||||
}
|
||||
ser.write(temp);
|
||||
|
||||
if value == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for Vec<u8> {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let length: i32 = deser.read::<VarInt>()?.into();
|
||||
if length < 0 {
|
||||
return Err("String length cannot be negative.".to_string());
|
||||
}
|
||||
|
||||
let length = length as usize;
|
||||
if length > MAX_CLIENT_PACKET_SIZE {
|
||||
return Err("Byte array was too long.".to_string());
|
||||
}
|
||||
|
||||
let mut it = Vec::with_capacity(length);
|
||||
it.resize(length, 0);
|
||||
deser.read_exact(it.as_mut_slice())?;
|
||||
|
||||
Ok(it)
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(VarInt(self.len() as i32));
|
||||
ser.write_exact(self.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketData for String {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let bytes = deser.read()?;
|
||||
String::from_utf8(bytes).map_err(|_| "String contained invalid UTF-8.".to_string())
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.clone().into_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PacketJson: DeserializeOwned + Serialize + Sized { }
|
||||
|
||||
impl PacketJson for crate::net::chat::Chat { }
|
||||
|
||||
impl<S: PacketJson> PacketData for S {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let bytes = deser.read::<Vec<u8>>()?;
|
||||
serde_json::from_slice(&bytes).map_err(|_| "Bad JSON syntax".to_string())
|
||||
}
|
||||
|
||||
fn write(&self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(serde_json::to_vec(self).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PacketSerializer: Sized {
|
||||
/// Write a slice of bytes directly, without a length prefix.
|
||||
fn write_exact(&mut self, value: &[u8]);
|
||||
fn write_eof(&mut self);
|
||||
|
||||
fn write<D: PacketData>(&mut self, value: D) {
|
||||
fn write<D: PacketWritable>(&mut self, value: D) {
|
||||
value.write(self)
|
||||
}
|
||||
}
|
||||
|
@ -286,13 +18,15 @@ impl PacketSerializer for Vec<u8> {
|
|||
fn write_exact(&mut self, value: &[u8]) {
|
||||
self.extend_from_slice(value);
|
||||
}
|
||||
|
||||
fn write_eof(&mut self) {}
|
||||
}
|
||||
|
||||
pub trait PacketDeserializer: Sized {
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), String>;
|
||||
fn read_eof(&mut self) -> Result<(), String>;
|
||||
|
||||
fn read<D: PacketData>(&mut self) -> Result<D, String> {
|
||||
fn read<D: PacketReadable>(&mut self) -> Result<D, String> {
|
||||
D::read(self)
|
||||
}
|
||||
}
|
||||
|
@ -332,3 +66,232 @@ impl PacketDeserializer for VecPacketDeserializer<'_> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PacketReadable: Sized {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String>;
|
||||
}
|
||||
|
||||
pub trait PacketWritable {
|
||||
fn write(self, ser: &mut impl PacketSerializer);
|
||||
}
|
||||
|
||||
pub trait PacketData: PacketReadable + PacketWritable {}
|
||||
impl<T: PacketReadable + PacketWritable> PacketData for T {}
|
||||
|
||||
impl PacketReadable for bool {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let value = deser.read::<u8>()?;
|
||||
match value {
|
||||
0x00 => Ok(false),
|
||||
0x01 => Ok(true),
|
||||
n => Err(format!("{:0X} is not a valid boolean.", n))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWritable for bool {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self as u8);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_packet_data_for_num {
|
||||
( $( $num:ty, $len:expr );+ ) => {
|
||||
$(
|
||||
impl PacketReadable for $num {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<[u8; $len]>().map(Self::from_be_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWritable for $num {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.to_be_bytes())
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_packet_data_for_num!(u8, 1; i8, 1; u16, 2; i16, 2; u32, 4; i32, 4; u64, 8; i64, 8;
|
||||
f32, 4; f64, 8);
|
||||
|
||||
// HACK: There is probably a better solution to this than a macro.
|
||||
// Same goes for the above, but to a lesser degree.
|
||||
macro_rules! impl_varnum {
|
||||
( $( $name:ident, $wraps:ty, $length:expr);+ ) => {
|
||||
$(
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct $name(pub $wraps);
|
||||
|
||||
impl From<$wraps> for $name {
|
||||
fn from(x: $wraps) -> Self { $name(x) }
|
||||
}
|
||||
|
||||
impl Into<$wraps> for $name {
|
||||
fn into(self) -> $wraps { self.0 }
|
||||
}
|
||||
|
||||
impl PacketReadable for $name {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let mut length = 1;
|
||||
let mut acc = 0;
|
||||
while length <= $length {
|
||||
// If the highest bit is set, there are further bytes to be read;
|
||||
// the rest of the bits are the actual bits of the number.
|
||||
let read = deser.read::<u8>()?;
|
||||
acc |= (read & 0b01111111) as $wraps;
|
||||
|
||||
if (read & 0b10000000) == 0 {
|
||||
// There are no more bytes.
|
||||
return Ok($name(acc));
|
||||
}
|
||||
|
||||
// Make space for the rest of the bits.
|
||||
acc = acc << 7;
|
||||
length += 1;
|
||||
}
|
||||
|
||||
Err(format!("VarNum was more than {} bytes.", $length))
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWritable for $name {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
let mut value = self.0;
|
||||
loop {
|
||||
let mut temp = (value & 0b01111111) as u8;
|
||||
value = value >> 7;
|
||||
if value != 0 {
|
||||
temp |= 0b10000000;
|
||||
}
|
||||
ser.write(temp);
|
||||
|
||||
if value == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl_varnum!(VarInt, i32, 5; VarLong, i64, 10);
|
||||
|
||||
impl PacketWritable for &[u8] {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(VarInt(self.len() as i32));
|
||||
ser.write_exact(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketReadable for Vec<u8> {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let length: i32 = deser.read::<VarInt>()?.into();
|
||||
if length < 0 {
|
||||
return Err("String length cannot be negative.".to_string());
|
||||
}
|
||||
|
||||
let length = length as usize;
|
||||
if length > MAX_CLIENT_PACKET_SIZE {
|
||||
return Err("Byte array was too long.".to_string());
|
||||
}
|
||||
|
||||
let mut it = Vec::with_capacity(length);
|
||||
it.resize(length, 0);
|
||||
deser.read_exact(it.as_mut_slice())?;
|
||||
|
||||
Ok(it)
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWritable for &Vec<u8> {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketReadable for Box<[u8]> {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<Vec<u8>>().map(|x| x.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWritable for &Box<[u8]> {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write::<&[u8]>(self.borrow());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWritable for &str {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(self.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketReadable for String {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let bytes = deser.read()?;
|
||||
String::from_utf8(bytes).map_err(|_| "String contained invalid UTF-8.".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWritable for &String {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write::<&str>(self.borrow());
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketReadable for Box<str> {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
deser.read::<String>().map(|x| x.into_boxed_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWritable for &Box<str> {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write::<&str>(self.borrow());
|
||||
}
|
||||
}
|
||||
|
||||
/// A marker trait indicating that a JSON-serialiable type should be serialized as JSON in packets.
|
||||
/// Most primitive types are already serializable as JSON,
|
||||
/// but we explicitly *don't* want to serialize them as JSON in packets.
|
||||
pub trait PacketJson { }
|
||||
|
||||
impl PacketJson for crate::net::chat::Chat { }
|
||||
|
||||
impl<S: DeserializeOwned + PacketJson + Sized> PacketReadable for S {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
let bytes = deser.read::<Vec<u8>>()?;
|
||||
serde_json::from_slice(&bytes).map_err(|_| "Bad JSON syntax".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: PacketJson + Serialize> PacketWritable for &S {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write(&serde_json::to_vec(self).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
// Although according to my organizational scheme, this should go first,
|
||||
// it goes last anyway because constant generics break Atom's syntax highlighting
|
||||
// for all code below it.
|
||||
|
||||
impl<const N: usize> PacketReadable for [u8; N] {
|
||||
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
|
||||
use std::convert::TryInto;
|
||||
|
||||
let mut buf = [0; N];
|
||||
deser.read_exact(&mut buf)?;
|
||||
Ok(buf.try_into().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<const N: usize> PacketWritable for [u8; N] {
|
||||
fn write(self, ser: &mut impl PacketSerializer) {
|
||||
ser.write_exact(&self);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
use crate::net::serialize::{PacketDeserializer, PacketSerializer};
|
||||
|
||||
pub trait ProtocolState: Sized {
|
||||
/// Get a packet's id.
|
||||
fn id(&self) -> i32;
|
||||
/// Read a packet from the deserializer.
|
||||
fn read(id: i32, deser: &mut impl PacketDeserializer) -> Result<Self, String>;
|
||||
/// Write this packet's data to the serializer.
|
||||
fn write(&self, ser: &mut impl PacketSerializer);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! define_states {
|
||||
{ $( state $name:ident { $( $id:expr => $packet:ident ),* } )+ } => {
|
||||
$(
|
||||
pub enum $name {
|
||||
$( $packet($packet) ),*
|
||||
}
|
||||
|
||||
impl crate::net::state::ProtocolState for $name {
|
||||
fn id(&self) -> i32 {
|
||||
match *self {
|
||||
$( $name::$packet(_) => $id ),*
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn read(id: i32, deser: &mut impl crate::net::serialize::PacketDeserializer) -> Result<Self, String> {
|
||||
match id {
|
||||
$( $id => deser.read::<$packet>().map($name::$packet), )*
|
||||
id => Err(format!("Invalid packet id: {}", id))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn write(&self, ser: &mut impl crate::net::serialize::PacketSerializer) {
|
||||
match *self {
|
||||
$( $name::$packet(ref pkt) => ser.write(pkt) ),*
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue