Correctly distinguish packet maps and protocol states.

master
James T. Martin 2020-07-25 00:26:30 -07:00
parent 2a0f97be29
commit afc8a4aaaa
Signed by: james
GPG Key ID: 4B7F3DA9351E577C
9 changed files with 124 additions and 132 deletions

View File

@ -4,7 +4,9 @@
mod net;
use crate::net::chat::Chat;
use crate::net::connection::{Connection, StateHandshake, StateStatus};
use crate::net::connection::Connection;
use crate::net::state::handshake::Handshake;
use crate::net::state::status::Status;
use tokio::net::{TcpListener, TcpStream};
use std::io;
use std::net::IpAddr;
@ -52,11 +54,11 @@ async fn accept_connection(socket: TcpStream) {
}
}
async fn interact_handshake<'a>(mut con: Connection<StateHandshake>) -> io::Result<()> {
use crate::net::packet::handshake::*;
async fn interact_handshake<'a>(mut con: Connection<Handshake>) -> io::Result<()> {
use crate::net::state::handshake::*;
match con.read().await? {
HandshakeServerbound::Handshake(handshake) => {
Serverbound::HandshakePkt(handshake) => {
use HandshakeNextState::*;
match handshake.next_state {
@ -67,13 +69,13 @@ async fn interact_handshake<'a>(mut con: Connection<StateHandshake>) -> io::Resu
}
}
async fn interact_status<'a>(mut con: Connection<StateStatus>) -> io::Result<()> {
use crate::net::packet::status::*;
async fn interact_status<'a>(mut con: Connection<Status>) -> io::Result<()> {
use crate::net::state::status::*;
loop {
match con.read().await? {
StatusServerbound::Request(Request {}) => {
con.write(&StatusClientbound::Response(Response {
Serverbound::Request(Request {}) => {
con.write(&Clientbound::Response(Response {
data: ResponseData {
version: ResponseVersion {
name: "1.16.1".to_string(),
@ -89,8 +91,8 @@ async fn interact_status<'a>(mut con: Connection<StateStatus>) -> io::Result<()>
}
})).await?;
},
StatusServerbound::Ping(ping) => {
con.write(&StatusClientbound::Pong(Pong {
Serverbound::Ping(ping) => {
con.write(&Clientbound::Pong(Pong {
payload: ping.payload
})).await?;

View File

@ -1,64 +1,24 @@
use crate::net::{Reader, Writer};
use crate::net::format::{PacketFormat, DefaultPacketFormat};
use crate::net::state::ProtocolState;
use crate::net::packet::handshake::{HandshakeClientbound, HandshakeServerbound};
use crate::net::packet::status::{StatusClientbound, StatusServerbound};
use crate::net::state::handshake::Handshake;
use crate::net::state::status::Status;
use std::io;
use std::marker::PhantomData;
use tokio::net::TcpStream;
pub trait State {
type Clientbound: ProtocolState + Sync;
type Serverbound: ProtocolState + Sync;
}
#[allow(dead_code)]
pub enum StateHandshake {}
impl State for StateHandshake {
type Clientbound = HandshakeClientbound;
type Serverbound = HandshakeServerbound;
}
#[allow(dead_code)]
pub enum StateStatus {}
impl State for StateStatus {
type Clientbound = StatusClientbound;
type Serverbound = StatusServerbound;
}
#[allow(dead_code)]
pub enum StateDisconnected {}
impl State for StateDisconnected {
type Clientbound = !;
type Serverbound = !;
}
#[allow(dead_code)]
pub enum StateLogin {}
impl State for StateLogin {
type Clientbound = !;
type Serverbound = !;
}
#[allow(dead_code)]
pub enum StatePlay {}
impl State for StatePlay {
type Clientbound = !;
type Serverbound = !;
}
pub struct Connection<St: State> {
pub struct Connection<St: ProtocolState> {
src: Reader,
dest: Writer,
st: PhantomData<St>,
}
impl<St: State> Connection<St> {
// Placeholders until I implement these protocol states.
use crate::define_state;
define_state!(Login, !, !);
define_state!(Play, !, !);
impl<St: ProtocolState> Connection<St> {
pub async fn write(&mut self, pkt: &St::Clientbound) -> io::Result<()> {
DefaultPacketFormat.send::<St::Clientbound>(&mut self.dest, pkt).await
}
@ -67,7 +27,7 @@ impl<St: State> Connection<St> {
DefaultPacketFormat.recieve::<St::Serverbound>(&mut self.src).await
}
pub fn into_disconnected(self) -> Connection<StateDisconnected> {
pub fn into_disconnected(self) -> Connection<!> {
Connection {
src: self.src,
dest: self.dest,
@ -76,7 +36,7 @@ impl<St: State> Connection<St> {
}
}
impl Connection<StateHandshake> {
impl Connection<Handshake> {
pub fn new(stream: TcpStream) -> Self {
use tokio::io::{BufReader, BufWriter};
@ -89,7 +49,7 @@ impl Connection<StateHandshake> {
}
}
pub fn into_status(self) -> Connection<StateStatus> {
pub fn into_status(self) -> Connection<Status> {
Connection {
src: self.src,
dest: self.dest,
@ -97,7 +57,7 @@ impl Connection<StateHandshake> {
}
}
pub fn into_login(self) -> Connection<StateLogin> {
pub fn into_login(self) -> Connection<Login> {
Connection {
src: self.src,
dest: self.dest,
@ -106,8 +66,8 @@ impl Connection<StateHandshake> {
}
}
impl Connection<StateLogin> {
pub fn into_play(self) -> Connection<StatePlay> {
impl Connection<Login> {
pub fn into_play(self) -> Connection<Play> {
Connection {
src: self.src,
dest: self.dest,

View File

@ -1,14 +1,14 @@
use async_trait::async_trait;
use crate::net::{Reader, Writer};
use crate::net::state::ProtocolState;
use crate::net::packet_map::PacketMap;
use std::boxed::Box;
use std::io;
use tokio::io::AsyncReadExt;
#[async_trait]
pub trait PacketFormat {
async fn send<P: ProtocolState + Sync>(&self, dest: &mut Writer, pkt: &P) -> io::Result<()>;
async fn recieve<P: ProtocolState>(&self, src: &mut Reader) -> io::Result<P>;
async fn send<P: PacketMap>(&self, dest: &mut Writer, pkt: &P) -> io::Result<()>;
async fn recieve<P: PacketMap>(&self, src: &mut Reader) -> io::Result<P>;
}
pub const MAX_CLIENT_PACKET_SIZE: usize = 32767;
@ -35,7 +35,7 @@ async fn read_varint(src: &mut Reader) -> io::Result<(usize, i32)> {
#[async_trait]
impl PacketFormat for DefaultPacketFormat {
async fn send<P: ProtocolState + Sync>(&self, dest: &mut Writer, pkt: &P) -> io::Result<()> {
async fn send<P: PacketMap>(&self, dest: &mut Writer, pkt: &P) -> io::Result<()> {
use crate::net::serialize::{PacketSerializer, VarInt};
let packet_id = pkt.id();
@ -61,7 +61,7 @@ impl PacketFormat for DefaultPacketFormat {
Ok(())
}
async fn recieve<P: ProtocolState>(&self, src: &mut Reader) -> io::Result<P> {
async fn recieve<P: PacketMap>(&self, src: &mut Reader) -> io::Result<P> {
use crate::net::serialize::VecPacketDeserializer;
let (_, length) = read_varint(src).await?;

View File

@ -2,11 +2,12 @@ pub mod chat;
pub mod connection;
pub mod format;
pub mod packet;
pub mod packet_map;
pub mod serialize;
pub mod state;
use tokio::io::{BufReader, BufWriter};
use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf};
pub type Reader= BufReader<OwnedReadHalf>;
pub type Reader = BufReader<OwnedReadHalf>;
pub type Writer = BufWriter<OwnedWriteHalf>;

View File

@ -1,6 +1,3 @@
pub mod handshake;
pub mod status;
#[macro_export]
macro_rules! define_packets {
{ $( packet $name:ident { $( $field:ident : $type:ty ),* } )+ } => {

59
src/net/packet_map.rs Normal file
View File

@ -0,0 +1,59 @@
use crate::net::serialize::{PacketDeserializer, PacketSerializer};
pub trait PacketMap: Sized + Sync {
/// 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);
}
impl PacketMap for ! {
fn id(&self) -> i32 {
match *self { }
}
fn read(_id: i32, _deser: &mut impl PacketDeserializer) -> Result<Self, String> {
Err("Cannot read packets; the connection state is disconnected.".to_string())
}
fn write(&self, _ser: &mut impl PacketSerializer) {
match *self { }
}
}
#[macro_export]
macro_rules! define_packet_maps {
{ $( packet_map $name:ident { $( $id:expr => $packet:ident ),* } )+ } => {
$(
pub enum $name {
$( $packet($packet) ),*
}
impl crate::net::packet_map::PacketMap 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) ),*
}
}
}
)*
}
}

View File

@ -1,58 +1,27 @@
use crate::net::serialize::{PacketDeserializer, PacketSerializer};
pub mod handshake;
pub mod status;
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);
use crate::net::packet_map::PacketMap;
pub trait ProtocolState {
type Clientbound: PacketMap;
type Serverbound: PacketMap;
}
impl ProtocolState for ! {
fn id(&self) -> i32 {
match *self { }
}
fn read(_id: i32, _deser: &mut impl PacketDeserializer) -> Result<Self, String> {
Err("Cannot read packets; the connection state is disconnected.".to_string())
}
fn write(&self, _ser: &mut impl PacketSerializer) {
match *self { }
}
type Clientbound = !;
type Serverbound = !;
}
#[macro_export]
macro_rules! define_states {
{ $( state $name:ident { $( $id:expr => $packet:ident ),* } )+ } => {
$(
pub enum $name {
$( $packet($packet) ),*
}
macro_rules! define_state {
( $name:ident , $cb:ty , $sb:ty ) => {
#[allow(dead_code)]
pub enum $name {}
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) ),*
}
}
}
)*
impl crate::net::state::ProtocolState for $name {
type Clientbound = $cb;
type Serverbound = $sb;
}
}
}

View File

@ -1,4 +1,4 @@
use crate::{define_packets, define_states};
use crate::{define_packets, define_packet_maps, define_state};
use crate::net::serialize::{PacketReadable, PacketWritable, PacketDeserializer, PacketSerializer, VarInt};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -31,7 +31,7 @@ impl PacketWritable for &HandshakeNextState {
}
define_packets! {
packet Handshake {
packet HandshakePkt {
protocol_version: VarInt,
server_address: String,
server_port: u16,
@ -39,10 +39,12 @@ define_packets! {
}
}
define_states! {
state HandshakeClientbound { }
define_packet_maps! {
packet_map Clientbound { }
state HandshakeServerbound {
0x00 => Handshake
packet_map Serverbound {
0x00 => HandshakePkt
}
}
define_state!(Handshake, Clientbound, Serverbound);

View File

@ -1,4 +1,4 @@
use crate::{define_packets, define_states};
use crate::{define_packets, define_packet_maps, define_state};
use crate::net::chat::Chat;
use crate::net::serialize::{PacketJson};
use serde::{Deserialize, Serialize};
@ -56,14 +56,16 @@ define_packets! {
}
}
define_states! {
state StatusClientbound {
define_packet_maps! {
packet_map Clientbound {
0x00 => Response,
0x01 => Pong
}
state StatusServerbound {
packet_map Serverbound {
0x00 => Request,
0x01 => Ping
}
}
define_state!(Status, Clientbound, Serverbound);