diff --git a/azalea-client/src/connect.rs b/azalea-client/src/connect.rs index 7e6dba51..6e58bee6 100755 --- a/azalea-client/src/connect.rs +++ b/azalea-client/src/connect.rs @@ -48,10 +48,18 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> { println!("Got profile {:?}", p.game_profile); break conn.game(); } - _ => panic!("unhandled packet"), + LoginPacket::ServerboundHelloPacket(p) => { + println!("Got hello {:?}", p); + } + LoginPacket::ClientboundLoginDisconnectPacket(p) => { + println!("Got disconnect {:?}", p); + } + LoginPacket::ClientboundCustomQueryPacket(p) => { + println!("Got custom query {:?}", p); + } }, Err(e) => { - println!("Error: {:?}", e); + panic!("Error: {:?}", e); } } }; @@ -85,6 +93,9 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> { GamePacket::ClientboundUpdateTagsPacket(p) => { println!("Got update tags packet {:?}", p); } + GamePacket::ClientboundDisconnectPacket(p) => { + println!("Got login disconnect packet {:?}", p); + } }, Err(e) => { panic!("Error: {:?}", e); diff --git a/azalea-protocol/src/mc_buf/mod.rs b/azalea-protocol/src/mc_buf/mod.rs index a924431e..4ecb65d1 100755 --- a/azalea-protocol/src/mc_buf/mod.rs +++ b/azalea-protocol/src/mc_buf/mod.rs @@ -19,21 +19,53 @@ mod tests { #[test] fn test_write_varint() { - let mut buf = Vec::new(); - buf.write_varint(123456).unwrap(); - assert_eq!(buf, vec![192, 196, 7]); - let mut buf = Vec::new(); buf.write_varint(0).unwrap(); assert_eq!(buf, vec![0]); + + let mut buf = Vec::new(); + buf.write_varint(1).unwrap(); + assert_eq!(buf, vec![1]); + + let mut buf = Vec::new(); + buf.write_varint(2).unwrap(); + assert_eq!(buf, vec![2]); + + let mut buf = Vec::new(); + buf.write_varint(127).unwrap(); + assert_eq!(buf, vec![127]); + + let mut buf = Vec::new(); + buf.write_varint(128).unwrap(); + assert_eq!(buf, vec![128, 1]); + + let mut buf = Vec::new(); + buf.write_varint(255).unwrap(); + assert_eq!(buf, vec![255, 1]); + + let mut buf = Vec::new(); + buf.write_varint(25565).unwrap(); + assert_eq!(buf, vec![221, 199, 1]); + + let mut buf = Vec::new(); + buf.write_varint(2097151).unwrap(); + assert_eq!(buf, vec![255, 255, 127]); + + let mut buf = Vec::new(); + buf.write_varint(2147483647).unwrap(); + assert_eq!(buf, vec![255, 255, 255, 255, 7]); + + let mut buf = Vec::new(); + buf.write_varint(-1).unwrap(); + assert_eq!(buf, vec![255, 255, 255, 255, 15]); + + let mut buf = Vec::new(); + buf.write_varint(-2147483648).unwrap(); + assert_eq!(buf, vec![128, 128, 128, 128, 8]); } #[tokio::test] async fn test_read_varint() { - let mut buf = BufReader::new(Cursor::new(vec![192, 196, 7])); - assert_eq!(buf.read_varint().await.unwrap(), 123456); - assert_eq!(buf.get_varint_size(123456), 3); - let mut buf = BufReader::new(Cursor::new(vec![0])); assert_eq!(buf.read_varint().await.unwrap(), 0); assert_eq!(buf.get_varint_size(0), 1); @@ -41,6 +73,42 @@ mod tests { let mut buf = BufReader::new(Cursor::new(vec![1])); assert_eq!(buf.read_varint().await.unwrap(), 1); assert_eq!(buf.get_varint_size(1), 1); + + let mut buf = BufReader::new(Cursor::new(vec![2])); + assert_eq!(buf.read_varint().await.unwrap(), 2); + assert_eq!(buf.get_varint_size(2), 1); + + let mut buf = BufReader::new(Cursor::new(vec![127])); + assert_eq!(buf.read_varint().await.unwrap(), 127); + assert_eq!(buf.get_varint_size(127), 1); + + let mut buf = BufReader::new(Cursor::new(vec![128, 1])); + assert_eq!(buf.read_varint().await.unwrap(), 128); + assert_eq!(buf.get_varint_size(128), 2); + + let mut buf = BufReader::new(Cursor::new(vec![255, 1])); + assert_eq!(buf.read_varint().await.unwrap(), 255); + assert_eq!(buf.get_varint_size(255), 2); + + let mut buf = BufReader::new(Cursor::new(vec![221, 199, 1])); + assert_eq!(buf.read_varint().await.unwrap(), 25565); + assert_eq!(buf.get_varint_size(25565), 3); + + let mut buf = BufReader::new(Cursor::new(vec![255, 255, 127])); + assert_eq!(buf.read_varint().await.unwrap(), 2097151); + assert_eq!(buf.get_varint_size(2097151), 3); + + let mut buf = BufReader::new(Cursor::new(vec![255, 255, 255, 255, 7])); + assert_eq!(buf.read_varint().await.unwrap(), 2147483647); + assert_eq!(buf.get_varint_size(2147483647), 5); + + let mut buf = BufReader::new(Cursor::new(vec![255, 255, 255, 255, 15])); + assert_eq!(buf.read_varint().await.unwrap(), -1); + assert_eq!(buf.get_varint_size(-1), 5); + + let mut buf = BufReader::new(Cursor::new(vec![128, 128, 128, 128, 8])); + assert_eq!(buf.read_varint().await.unwrap(), -2147483648); + assert_eq!(buf.get_varint_size(-2147483648), 5); } #[tokio::test] diff --git a/azalea-protocol/src/mc_buf/read.rs b/azalea-protocol/src/mc_buf/read.rs index e036643e..1e031916 100755 --- a/azalea-protocol/src/mc_buf/read.rs +++ b/azalea-protocol/src/mc_buf/read.rs @@ -1,7 +1,9 @@ use async_trait::async_trait; +use azalea_chat::component::Component; use azalea_core::{ difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation, }; +use serde::Deserialize; use tokio::io::{AsyncRead, AsyncReadExt}; use super::MAX_STRING_LENGTH; @@ -41,12 +43,12 @@ where Ok(list) } - // fast varints stolen from https://github.com/luojia65/mc-varint/blob/master/src/lib.rs#L67 + // fast varints modified from https://github.com/luojia65/mc-varint/blob/master/src/lib.rs#L67 /// Read a single varint from the reader and return the value, along with the number of bytes read async fn read_varint(&mut self) -> Result { let mut buffer = [0]; let mut ans = 0; - for i in 0..4 { + for i in 0..5 { self.read_exact(&mut buffer) .await .map_err(|_| "Invalid VarInt".to_string())?; @@ -440,3 +442,18 @@ impl McBufReadable for Difficulty { Ok(Difficulty::by_id(u8::read_into(buf).await?)) } } + +// Component +#[async_trait] +impl McBufReadable for Component { + async fn read_into(buf: &mut R) -> Result + where + R: AsyncRead + std::marker::Unpin + std::marker::Send, + { + let string = buf.read_utf().await?; + let json: serde_json::Value = serde_json::from_str(string.as_str()) + .map_err(|e| "Component isn't valid JSON".to_string())?; + let component = Component::deserialize(json).map_err(|e| e.to_string())?; + Ok(component) + } +} diff --git a/azalea-protocol/src/mc_buf/write.rs b/azalea-protocol/src/mc_buf/write.rs index 9330dccb..05f613d8 100755 --- a/azalea-protocol/src/mc_buf/write.rs +++ b/azalea-protocol/src/mc_buf/write.rs @@ -1,4 +1,5 @@ use async_trait::async_trait; +use azalea_chat::component::Component; use azalea_core::{ difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation, }; @@ -209,7 +210,7 @@ impl McBufWritable for ResourceLocation { // u32 impl McBufWritable for u32 { fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { - i32::varint_write_into(&(*self as i32), buf) + i16::write_into(&(*self as i16), buf) } } @@ -223,7 +224,7 @@ impl McBufVarintWritable for u32 { // u16 impl McBufWritable for u16 { fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { - i32::varint_write_into(&(*self as i32), buf) + i16::write_into(&(*self as i16), buf) } } @@ -241,6 +242,13 @@ impl McBufWritable for u8 { } } +// i16 +impl McBufWritable for i16 { + fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { + Writable::write_short(buf, *self) + } +} + // i64 impl McBufWritable for i64 { fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { @@ -269,7 +277,7 @@ impl McBufWritable for i8 { } } -// i8 +// f32 impl McBufWritable for f32 { fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { buf.write_float(*self) @@ -312,3 +320,22 @@ impl McBufWritable for Difficulty { u8::write_into(&self.id(), buf) } } + +// Component +#[async_trait] +impl McBufWritable for Component { + // async fn read_into(buf: &mut R) -> Result + // where + // R: AsyncRead + std::marker::Unpin + std::marker::Send, + // { + // let string = buf.read_utf().await?; + // let json: serde_json::Value = serde_json::from_str(string.as_str()) + // .map_err(|e| "Component isn't valid JSON".to_string())?; + // let component = Component::deserialize(json).map_err(|e| e.to_string())?; + // Ok(component) + // } + fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { + // component doesn't have serialize implemented yet + todo!() + } +} diff --git a/azalea-protocol/src/packets/game/clientbound_disconnect_packet.rs b/azalea-protocol/src/packets/game/clientbound_disconnect_packet.rs new file mode 100644 index 00000000..74f5f72e --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_disconnect_packet.rs @@ -0,0 +1,9 @@ +use azalea_chat::component::Component; +use azalea_core::resource_location::ResourceLocation; +use packet_macros::GamePacket; +use serde::Deserialize; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundDisconnectPacket { + pub reason: Component, +} diff --git a/azalea-protocol/src/packets/game/mod.rs b/azalea-protocol/src/packets/game/mod.rs index e150606c..dde3f753 100755 --- a/azalea-protocol/src/packets/game/mod.rs +++ b/azalea-protocol/src/packets/game/mod.rs @@ -1,6 +1,7 @@ pub mod clientbound_change_difficulty_packet; pub mod clientbound_custom_payload_packet; pub mod clientbound_declare_commands_packet; +pub mod clientbound_disconnect_packet; pub mod clientbound_login_packet; pub mod clientbound_player_abilities_packet; pub mod clientbound_set_carried_item_packet; @@ -15,6 +16,7 @@ declare_state_packets!( Clientbound => { 0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket, 0x12: clientbound_declare_commands_packet::ClientboundDeclareCommandsPacket, + 0x1a: clientbound_disconnect_packet::ClientboundDisconnectPacket, 0x18: clientbound_custom_payload_packet::ClientboundCustomPayloadPacket, 0x26: clientbound_login_packet::ClientboundLoginPacket, 0x32: clientbound_player_abilities_packet::ClientboundPlayerAbilitiesPacket, diff --git a/azalea-protocol/src/packets/handshake/client_intention_packet.rs b/azalea-protocol/src/packets/handshake/client_intention_packet.rs index 6216ddc4..a92d65f6 100755 --- a/azalea-protocol/src/packets/handshake/client_intention_packet.rs +++ b/azalea-protocol/src/packets/handshake/client_intention_packet.rs @@ -1,7 +1,9 @@ -use crate::packets::ConnectionProtocol; +use crate::{mc_buf::Writable, packets::ConnectionProtocol}; use packet_macros::HandshakePacket; use std::hash::Hash; +use super::HandshakePacket; + #[derive(Hash, Clone, Debug, HandshakePacket)] pub struct ClientIntentionPacket { #[varint] @@ -10,3 +12,23 @@ pub struct ClientIntentionPacket { pub port: u16, pub intention: ConnectionProtocol, } + +// impl ClientIntentionPacket { +// pub fn get(self) -> HandshakePacket { +// HandshakePacket::ClientIntentionPacket(self) +// } + +// pub fn write(&self, buf: &mut Vec) -> Result<(), std::io::Error> { +// buf.write_varint(self.protocol_version as i32)?; +// buf.write_utf(&self.hostname)?; +// buf.write_short(self.port as i16)?; +// buf.write_varint(self.intention as i32)?; +// Ok(()) +// } + +// pub async fn read( +// buf: &mut T, +// ) -> Result { +// todo!() +// } +// } diff --git a/azalea-protocol/src/packets/login/clientbound_login_disconnect_packet.rs b/azalea-protocol/src/packets/login/clientbound_login_disconnect_packet.rs new file mode 100644 index 00000000..28d91c79 --- /dev/null +++ b/azalea-protocol/src/packets/login/clientbound_login_disconnect_packet.rs @@ -0,0 +1,7 @@ +use azalea_chat::component::Component; +use packet_macros::LoginPacket; + +#[derive(Clone, Debug, LoginPacket)] +pub struct ClientboundLoginDisconnectPacket { + pub reason: Component, +} diff --git a/azalea-protocol/src/packets/login/mod.rs b/azalea-protocol/src/packets/login/mod.rs index ef5f15c1..ab68518c 100755 --- a/azalea-protocol/src/packets/login/mod.rs +++ b/azalea-protocol/src/packets/login/mod.rs @@ -2,6 +2,7 @@ pub mod clientbound_custom_query_packet; pub mod clientbound_game_profile_packet; pub mod clientbound_hello_packet; pub mod clientbound_login_compression_packet; +pub mod clientbound_login_disconnect_packet; pub mod serverbound_hello_packet; use packet_macros::declare_state_packets; @@ -12,7 +13,9 @@ declare_state_packets!( 0x00: serverbound_hello_packet::ServerboundHelloPacket, }, Clientbound => { - 0x00: clientbound_hello_packet::ClientboundHelloPacket, + // 0x00: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket, + 26: clientbound_login_disconnect_packet::ClientboundLoginDisconnectPacket, + 0x01: clientbound_hello_packet::ClientboundHelloPacket, 0x02: clientbound_game_profile_packet::ClientboundGameProfilePacket, 0x03: clientbound_login_compression_packet::ClientboundLoginCompressionPacket, 0x04: clientbound_custom_query_packet::ClientboundCustomQueryPacket, diff --git a/azalea-protocol/src/packets/mod.rs b/azalea-protocol/src/packets/mod.rs index f35451c6..98741a75 100755 --- a/azalea-protocol/src/packets/mod.rs +++ b/azalea-protocol/src/packets/mod.rs @@ -12,9 +12,9 @@ use num_derive::FromPrimitive; use num_traits::FromPrimitive; use tokio::io::AsyncRead; -pub const PROTOCOL_VERSION: u32 = 757; +pub const PROTOCOL_VERSION: u32 = 758; -#[derive(Debug, Clone, PartialEq, Eq, Hash, FromPrimitive)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromPrimitive)] pub enum ConnectionProtocol { Handshake = -1, Game = 0, @@ -63,6 +63,6 @@ impl McBufReadable for ConnectionProtocol { impl McBufWritable for ConnectionProtocol { fn write_into(&self, buf: &mut Vec) -> Result<(), std::io::Error> { - buf.write_varint(self.clone() as i32) + buf.write_varint(*self as i32) } } diff --git a/bot/src/main.rs b/bot/src/main.rs index 011c7d0d..7d129478 100755 --- a/bot/src/main.rs +++ b/bot/src/main.rs @@ -2,8 +2,8 @@ async fn main() { println!("Hello, world!"); - let address = "95.111.249.143:10000"; - // let address = "localhost:63482"; + // let address = "95.111.249.143:10000"; + let address = "localhost:52400"; // let response = azalea_client::ping::ping_server(&address.try_into().unwrap()) // .await // .unwrap();