Correctly distinguish packet maps and protocol states.
parent
2a0f97be29
commit
afc8a4aaaa
22
src/main.rs
22
src/main.rs
|
@ -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?;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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?;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
pub mod handshake;
|
||||
pub mod status;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! define_packets {
|
||||
{ $( packet $name:ident { $( $field:ident : $type:ty ),* } )+ } => {
|
||||
|
|
|
@ -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) ),*
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
Loading…
Reference in New Issue