diff --git a/Cargo.lock b/Cargo.lock index 3847548f..f2728389 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,6 +300,13 @@ dependencies = [ "minecraft-protocol", ] +[[package]] +name = "minecraft-core" +version = "0.1.0" +dependencies = [ + "uuid", +] + [[package]] name = "minecraft-protocol" version = "0.1.0" @@ -728,6 +735,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 97b864f4..a4ad743a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,9 @@ [workspace] members = [ - "bot", - "minecraft-client", - "minecraft-protocol", - "minecraft-chat", -] \ No newline at end of file + "bot", + "minecraft-client", + "minecraft-protocol", + "minecraft-chat", + "minecraft-core", +] diff --git a/minecraft-client/src/connect.rs b/minecraft-client/src/connect.rs index c4a18f1e..5eedbf96 100644 --- a/minecraft-client/src/connect.rs +++ b/minecraft-client/src/connect.rs @@ -34,8 +34,7 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> { // encryption request loop { - let packet = conn.read().await.unwrap(); - match packet { + match conn.read().await.unwrap() { LoginPacket::ClientboundHelloPacket(encryption_request_packet) => { println!( "Got encryption request {:?} {:?}", diff --git a/minecraft-core/Cargo.toml b/minecraft-core/Cargo.toml new file mode 100644 index 00000000..e36cc03e --- /dev/null +++ b/minecraft-core/Cargo.toml @@ -0,0 +1,9 @@ +[package] +edition = "2021" +name = "minecraft-core" +version = "0.1.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +uuid = "^0.8.2" diff --git a/minecraft-core/src/lib.rs b/minecraft-core/src/lib.rs new file mode 100644 index 00000000..592988a3 --- /dev/null +++ b/minecraft-core/src/lib.rs @@ -0,0 +1,12 @@ +//! Random miscellaneous things like UUIDs + +mod serializable_uuid; + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + let result = 2 + 2; + assert_eq!(result, 4); + } +} diff --git a/minecraft-core/src/serializable_uuid.rs b/minecraft-core/src/serializable_uuid.rs new file mode 100644 index 00000000..91b5f2d8 --- /dev/null +++ b/minecraft-core/src/serializable_uuid.rs @@ -0,0 +1,54 @@ +use uuid::Uuid; + +pub trait SerializableUuid { + fn to_int_array(&self) -> [u32; 4]; + fn from_int_array(array: [u32; 4]) -> Self; +} + +// private static int[] leastMostToIntArray(long l, long l2) { +// return new int[]{(int)(l >> 32), (int)l, (int)(l2 >> 32), (int)l2}; +// } + +fn least_most_to_int_array(most: u64, least: u64) -> [u32; 4] { + [ + (most >> 32) as u32, + most as u32, + (least >> 32) as u32, + least as u32, + ] +} + +impl SerializableUuid for Uuid { + fn to_int_array(&self) -> [u32; 4] { + let most_significant_bits = (self.as_u128() >> 64) as u64; + let least_significant_bits = (self.as_u128() & 0xffffffffffffffff) as u64; + + least_most_to_int_array(most_significant_bits, least_significant_bits) + } + + fn from_int_array(array: [u32; 4]) -> Self { + let most = ((array[0] as u64) << 32) | ((array[1] as u64) & 0xFFFFFFFF); + let least = ((array[2] as u64) << 32) | ((array[3] as u64) & 0xFFFFFFFF); + + Uuid::from_u128((((most as u128) << 64) | least as u128).into()) + } +} + +mod tests { + use super::*; + + #[test] + fn to_int_array() { + let u = Uuid::parse_str("6536bfed-8695-48fd-83a1-ecd24cf2a0fd").unwrap(); + assert_eq!( + u.to_int_array(), + [0x6536bfed, 0x869548fd, 0x83a1ecd2, 0x4cf2a0fd] + ); + } + + #[test] + fn from_int_array() { + let u = Uuid::from_int_array([0x6536bfed, 0x869548fd, 0x83a1ecd2, 0x4cf2a0fd]); + assert_eq!(u.to_string(), "6536bfed-8695-48fd-83a1-ecd24cf2a0fd"); + } +} diff --git a/minecraft-protocol/src/packets/login/clientbound_custom_query_packet.rs b/minecraft-protocol/src/packets/login/clientbound_custom_query_packet.rs index 54f3dd14..093176eb 100644 --- a/minecraft-protocol/src/packets/login/clientbound_custom_query_packet.rs +++ b/minecraft-protocol/src/packets/login/clientbound_custom_query_packet.rs @@ -1,39 +1,41 @@ use std::hash::Hash; use tokio::io::BufReader; -use crate::mc_buf; +use crate::mc_buf::{self, Readable, Writable}; use super::LoginPacket; #[derive(Hash, Clone, Debug)] pub struct ClientboundCustomQueryPacket { - pub transacton_id: u32, - // TODO: this should be a resource location - pub identifier: String, - pub data: Vec, + pub transaction_id: u32, + // TODO: this should be a resource location + pub identifier: String, + pub data: Vec, } -impl ClientboundHelloPacket { +impl ClientboundCustomQueryPacket { pub fn get(self) -> LoginPacket { - LoginPacket::ClientboundHelloPacket(self) + LoginPacket::ClientboundCustomQueryPacket(self) } - pub fn write(&self, _buf: &mut Vec) { - panic!("ClientboundHelloPacket::write not implemented") + pub fn write(&self, buf: &mut Vec) { + buf.write_varint(self.transaction_id as i32).unwrap(); + buf.write_utf(&self.identifier).unwrap(); + buf.write_bytes(&self.data).unwrap(); } pub async fn read( buf: &mut BufReader, ) -> Result { - // let server_id = mc_buf::read_utf_with_len(buf, 20).await?; - // let public_key = mc_buf::read_byte_array(buf).await?; - // let nonce = mc_buf::read_byte_array(buf).await?; - - // Ok(ClientboundHelloPacket { - // server_id, - // public_key, - // nonce, - // } - // .get()) + let transaction_id = buf.read_varint().await?.0 as u32; + // TODO: this should be a resource location + let identifier = buf.read_utf().await?; + let data = buf.read_bytes(1048576).await?; + Ok(ClientboundCustomQueryPacket { + transaction_id, + identifier, + data, + } + .get()) } } diff --git a/minecraft-protocol/src/packets/login/mod.rs b/minecraft-protocol/src/packets/login/mod.rs index 70799e22..f0ed6717 100644 --- a/minecraft-protocol/src/packets/login/mod.rs +++ b/minecraft-protocol/src/packets/login/mod.rs @@ -1,3 +1,4 @@ +pub mod clientbound_custom_query_packet; pub mod clientbound_hello_packet; pub mod serverbound_hello_packet; @@ -13,6 +14,7 @@ pub enum LoginPacket where Self: Sized, { + ClientboundCustomQueryPacket(clientbound_custom_query_packet::ClientboundCustomQueryPacket), ServerboundHelloPacket(serverbound_hello_packet::ServerboundHelloPacket), ClientboundHelloPacket(clientbound_hello_packet::ClientboundHelloPacket), } @@ -21,6 +23,7 @@ where impl ProtocolPacket for LoginPacket { fn id(&self) -> u32 { match self { + LoginPacket::ClientboundCustomQueryPacket(_packet) => 0x04, LoginPacket::ServerboundHelloPacket(_packet) => 0x00, LoginPacket::ClientboundHelloPacket(_packet) => 0x01, } @@ -28,6 +31,7 @@ impl ProtocolPacket for LoginPacket { fn write(&self, buf: &mut Vec) { match self { + LoginPacket::ClientboundCustomQueryPacket(packet) => packet.write(buf), LoginPacket::ServerboundHelloPacket(packet) => packet.write(buf), LoginPacket::ClientboundHelloPacket(packet) => packet.write(buf), } @@ -42,15 +46,18 @@ impl ProtocolPacket for LoginPacket { where Self: Sized, { - match flow { + Ok(match flow { PacketFlow::ServerToClient => match id { - 0x01 => Ok(clientbound_hello_packet::ClientboundHelloPacket::read(buf).await?), - _ => Err(format!("Unknown ServerToClient status packet id: {}", id)), + 0x01 => clientbound_hello_packet::ClientboundHelloPacket::read(buf).await?, + 0x04 => { + clientbound_custom_query_packet::ClientboundCustomQueryPacket::read(buf).await? + } + _ => return Err(format!("Unknown ServerToClient status packet id: {}", id)), }, PacketFlow::ClientToServer => match id { - 0x00 => Ok(serverbound_hello_packet::ServerboundHelloPacket::read(buf).await?), - _ => Err(format!("Unknown ClientToServer status packet id: {}", id)), + 0x00 => serverbound_hello_packet::ServerboundHelloPacket::read(buf).await?, + _ => return Err(format!("Unknown ClientToServer status packet id: {}", id)), }, - } + }) } }