From 7b3e2e4bf793466a351510c7fbbd08234e93bb0e Mon Sep 17 00:00:00 2001 From: mat <27899617+mat-1@users.noreply.github.com> Date: Thu, 21 Sep 2023 11:16:29 -0500 Subject: 1.20.2 (#99) * add configuration state * start updating to 23w31a * implement a bit more of 23w31a * chunk batching * start adding configuration state * ioasfhjgsd * almost works * configuration state mostly implemented * handle other packets in configuration state and fix keepalive * cleanup, fix warnings * 23w32a * fix some doctests * 23w33a * 23w35a * 1.20.2-pre2 * fix system conflicts * 1.20.2-pre4 * make tests compile * tests pass * 1.20.2-rc2 * 1.20.2 * Revert "1.20.2" This reverts commit dd152fd265332ead333c919e585ded6d609d7468. * didn't mean to commit that code --------- Co-authored-by: mat --- azalea-protocol/src/connect.rs | 200 +++++++++++++++++++++++++++-------------- 1 file changed, 133 insertions(+), 67 deletions(-) (limited to 'azalea-protocol/src/connect.rs') diff --git a/azalea-protocol/src/connect.rs b/azalea-protocol/src/connect.rs index 5df1d874..9c573506 100755 --- a/azalea-protocol/src/connect.rs +++ b/azalea-protocol/src/connect.rs @@ -1,19 +1,23 @@ //! Connect to remote servers/clients. +use crate::packets::configuration::{ + ClientboundConfigurationPacket, ServerboundConfigurationPacket, +}; use crate::packets::game::{ClientboundGamePacket, ServerboundGamePacket}; -use crate::packets::handshake::{ClientboundHandshakePacket, ServerboundHandshakePacket}; +use crate::packets::handshaking::{ClientboundHandshakePacket, ServerboundHandshakePacket}; use crate::packets::login::clientbound_hello_packet::ClientboundHelloPacket; use crate::packets::login::{ClientboundLoginPacket, ServerboundLoginPacket}; use crate::packets::status::{ClientboundStatusPacket, ServerboundStatusPacket}; use crate::packets::ProtocolPacket; -use crate::read::{read_packet, try_read_packet, ReadPacketError}; -use crate::write::write_packet; +use crate::read::{deserialize_packet, read_raw_packet, try_read_raw_packet, ReadPacketError}; +use crate::write::{serialize_packet, write_raw_packet}; use azalea_auth::game_profile::GameProfile; use azalea_auth::sessionserver::{ClientSessionServerError, ServerSessionServerError}; use azalea_crypto::{Aes128CfbDec, Aes128CfbEnc}; use bytes::BytesMut; use log::{error, info}; use std::fmt::Debug; +use std::io::Cursor; use std::marker::PhantomData; use std::net::SocketAddr; use thiserror::Error; @@ -22,20 +26,28 @@ use tokio::net::tcp::{OwnedReadHalf, OwnedWriteHalf, ReuniteError}; use tokio::net::TcpStream; use uuid::Uuid; -/// The read half of a connection. -pub struct ReadConnection { +pub struct RawReadConnection { pub read_stream: OwnedReadHalf, pub buffer: BytesMut, pub compression_threshold: Option, pub dec_cipher: Option, - _reading: PhantomData, } -/// The write half of a connection. -pub struct WriteConnection { +pub struct RawWriteConnection { pub write_stream: OwnedWriteHalf, pub compression_threshold: Option, pub enc_cipher: Option, +} + +/// The read half of a connection. +pub struct ReadConnection { + pub raw: RawReadConnection, + _reading: PhantomData, +} + +/// The write half of a connection. +pub struct WriteConnection { + pub raw: RawWriteConnection, _writing: PhantomData, } @@ -55,7 +67,7 @@ pub struct WriteConnection { /// serverbound_hello_packet::ServerboundHelloPacket, /// serverbound_key_packet::ServerboundKeyPacket /// }, -/// handshake::client_intention_packet::ClientIntentionPacket +/// handshaking::client_intention_packet::ClientIntentionPacket /// } /// }; /// @@ -82,7 +94,7 @@ pub struct WriteConnection { /// conn.write( /// ServerboundHelloPacket { /// name: "bot".to_string(), -/// profile_id: None, +/// profile_id: uuid::Uuid::nil(), /// } /// .get(), /// ) @@ -108,7 +120,7 @@ pub struct WriteConnection { /// conn.set_compression_threshold(p.compression_threshold); /// } /// ClientboundLoginPacket::GameProfile(p) => { -/// break (conn.game(), p.game_profile); +/// break (conn.configuration(), p.game_profile); /// } /// ClientboundLoginPacket::LoginDisconnect(p) => { /// eprintln!("login disconnect: {}", p.reason); @@ -126,13 +138,9 @@ pub struct Connection { pub writer: WriteConnection, } -impl ReadConnection -where - R: ProtocolPacket + Debug, -{ - /// Read a packet from the stream. - pub async fn read(&mut self) -> Result> { - read_packet::( +impl RawReadConnection { + pub async fn read(&mut self) -> Result, Box> { + read_raw_packet::<_>( &mut self.read_stream, &mut self.buffer, self.compression_threshold, @@ -141,10 +149,8 @@ where .await } - /// Try to read a packet from the stream, or return Ok(None) if there's no - /// packet. - pub fn try_read(&mut self) -> Result, Box> { - try_read_packet::( + pub fn try_read(&mut self) -> Result>, Box> { + try_read_raw_packet::<_>( &mut self.read_stream, &mut self.buffer, self.compression_threshold, @@ -152,14 +158,11 @@ where ) } } -impl WriteConnection -where - W: ProtocolPacket + Debug, -{ - /// Write a packet to the server. - pub async fn write(&mut self, packet: W) -> std::io::Result<()> { - if let Err(e) = write_packet( - &packet, + +impl RawWriteConnection { + pub async fn write(&mut self, packet: &[u8]) -> std::io::Result<()> { + if let Err(e) = write_raw_packet( + packet, &mut self.write_stream, self.compression_threshold, &mut self.enc_cipher, @@ -184,6 +187,42 @@ where } } +impl ReadConnection +where + R: ProtocolPacket + Debug, +{ + /// Read a packet from the stream. + pub async fn read(&mut self) -> Result> { + let raw_packet = self.raw.read().await?; + deserialize_packet(&mut Cursor::new(raw_packet.as_slice())) + } + + /// Try to read a packet from the stream, or return Ok(None) if there's no + /// packet. + pub fn try_read(&mut self) -> Result, Box> { + let Some(raw_packet) = self.raw.try_read()? else { + return Ok(None); + }; + Ok(Some(deserialize_packet(&mut Cursor::new( + raw_packet.as_slice(), + ))?)) + } +} +impl WriteConnection +where + W: ProtocolPacket + Debug, +{ + /// Write a packet to the server. + pub async fn write(&mut self, packet: W) -> std::io::Result<()> { + self.raw.write(&serialize_packet(&packet).unwrap()).await + } + + /// End the connection. + pub async fn shutdown(&mut self) -> std::io::Result<()> { + self.raw.shutdown().await + } +} + impl Connection where R: ProtocolPacket + Debug, @@ -230,16 +269,20 @@ impl Connection { Ok(Connection { reader: ReadConnection { - read_stream, - buffer: BytesMut::new(), - compression_threshold: None, - dec_cipher: None, + raw: RawReadConnection { + read_stream, + buffer: BytesMut::new(), + compression_threshold: None, + dec_cipher: None, + }, _reading: PhantomData, }, writer: WriteConnection { - write_stream, - compression_threshold: None, - enc_cipher: None, + raw: RawWriteConnection { + write_stream, + compression_threshold: None, + enc_cipher: None, + }, _writing: PhantomData, }, }) @@ -267,11 +310,11 @@ impl Connection { pub fn set_compression_threshold(&mut self, threshold: i32) { // if you pass a threshold of less than 0, compression is disabled if threshold >= 0 { - self.reader.compression_threshold = Some(threshold as u32); - self.writer.compression_threshold = Some(threshold as u32); + self.reader.raw.compression_threshold = Some(threshold as u32); + self.writer.raw.compression_threshold = Some(threshold as u32); } else { - self.reader.compression_threshold = None; - self.writer.compression_threshold = None; + self.reader.raw.compression_threshold = None; + self.writer.raw.compression_threshold = None; } } @@ -279,14 +322,16 @@ impl Connection { /// the same for both reading and writing. pub fn set_encryption_key(&mut self, key: [u8; 16]) { let (enc_cipher, dec_cipher) = azalea_crypto::create_cipher(&key); - self.reader.dec_cipher = Some(dec_cipher); - self.writer.enc_cipher = Some(enc_cipher); + self.reader.raw.dec_cipher = Some(dec_cipher); + self.writer.raw.enc_cipher = Some(enc_cipher); } - /// Change our state from login to game. This is the state that's used when - /// you're actually in the game. + /// Change our state from login to configuration. This is the state where + /// the server sends us the registries and resource pack and stuff. #[must_use] - pub fn game(self) -> Connection { + pub fn configuration( + self, + ) -> Connection { Connection::from(self) } @@ -384,11 +429,11 @@ impl Connection { pub fn set_compression_threshold(&mut self, threshold: i32) { // if you pass a threshold of less than 0, compression is disabled if threshold >= 0 { - self.reader.compression_threshold = Some(threshold as u32); - self.writer.compression_threshold = Some(threshold as u32); + self.reader.raw.compression_threshold = Some(threshold as u32); + self.writer.raw.compression_threshold = Some(threshold as u32); } else { - self.reader.compression_threshold = None; - self.writer.compression_threshold = None; + self.reader.raw.compression_threshold = None; + self.writer.raw.compression_threshold = None; } } @@ -396,8 +441,8 @@ impl Connection { /// the same for both reading and writing. pub fn set_encryption_key(&mut self, key: [u8; 16]) { let (enc_cipher, dec_cipher) = azalea_crypto::create_cipher(&key); - self.reader.dec_cipher = Some(dec_cipher); - self.writer.enc_cipher = Some(enc_cipher); + self.reader.raw.dec_cipher = Some(dec_cipher); + self.writer.raw.enc_cipher = Some(enc_cipher); } /// Change our state from login to game. This is the state that's used when @@ -421,6 +466,25 @@ impl Connection { } } +impl Connection { + /// Change our state from configuration to game. This is the state that's + /// used when the client is actually in the world. + #[must_use] + pub fn game(self) -> Connection { + Connection::from(self) + } +} + +impl Connection { + /// Change our state back to configuration. + #[must_use] + pub fn configuration( + self, + ) -> Connection { + Connection::from(self) + } +} + // rust doesn't let us implement From because allegedly it conflicts with // `core`'s "impl From for T" so we do this instead impl Connection @@ -438,16 +502,11 @@ where { Connection { reader: ReadConnection { - read_stream: connection.reader.read_stream, - buffer: connection.reader.buffer, - compression_threshold: connection.reader.compression_threshold, - dec_cipher: connection.reader.dec_cipher, + raw: connection.reader.raw, _reading: PhantomData, }, writer: WriteConnection { - compression_threshold: connection.writer.compression_threshold, - write_stream: connection.writer.write_stream, - enc_cipher: connection.writer.enc_cipher, + raw: connection.writer.raw, _writing: PhantomData, }, } @@ -459,16 +518,20 @@ where Connection { reader: ReadConnection { - read_stream, - buffer: BytesMut::new(), - compression_threshold: None, - dec_cipher: None, + raw: RawReadConnection { + read_stream, + buffer: BytesMut::new(), + compression_threshold: None, + dec_cipher: None, + }, _reading: PhantomData, }, writer: WriteConnection { - write_stream, - compression_threshold: None, - enc_cipher: None, + raw: RawWriteConnection { + write_stream, + compression_threshold: None, + enc_cipher: None, + }, _writing: PhantomData, }, } @@ -476,6 +539,9 @@ where /// Convert from a `Connection` into a `TcpStream`. Useful for servers. pub fn unwrap(self) -> Result { - self.reader.read_stream.reunite(self.writer.write_stream) + self.reader + .raw + .read_stream + .reunite(self.writer.raw.write_stream) } } -- cgit v1.2.3