diff --git a/Cargo.lock b/Cargo.lock index b12a09d0..254dc5db 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,7 +75,6 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" name = "azalea-auth" version = "0.1.0" dependencies = [ - "num-bigint", "uuid", ] @@ -97,6 +96,7 @@ name = "azalea-client" version = "0.1.0" dependencies = [ "azalea-auth", + "azalea-core", "azalea-crypto", "azalea-protocol", "tokio", diff --git a/azalea-auth/Cargo.toml b/azalea-auth/Cargo.toml index 1015547b..aa9b7bdb 100755 --- a/azalea-auth/Cargo.toml +++ b/azalea-auth/Cargo.toml @@ -6,5 +6,4 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -num-bigint = "^0.4.3" uuid = "^0.8.2" diff --git a/azalea-client/Cargo.toml b/azalea-client/Cargo.toml index ab3f6eda..55caadeb 100755 --- a/azalea-client/Cargo.toml +++ b/azalea-client/Cargo.toml @@ -7,6 +7,7 @@ version = "0.1.0" [dependencies] azalea-auth = {path = "../azalea-auth"} +azalea-core = {path = "../azalea-core"} azalea-crypto = {path = "../azalea-crypto"} azalea-protocol = {path = "../azalea-protocol"} tokio = {version = "1.18.0", features = ["sync"]} diff --git a/azalea-client/src/connect.rs b/azalea-client/src/connect.rs index 7049ab81..2a5066c6 100755 --- a/azalea-client/src/connect.rs +++ b/azalea-client/src/connect.rs @@ -1,7 +1,9 @@ +use crate::Player; +use azalea_core::resource_location::ResourceLocation; use azalea_protocol::{ connect::{GameConnection, HandshakeConnection}, packets::{ - game::GamePacket, + game::{serverbound_custom_payload_packet::ServerboundCustomPayloadPacket, GamePacket}, handshake::client_intention_packet::ClientIntentionPacket, login::{ serverbound_hello_packet::ServerboundHelloPacket, @@ -15,8 +17,6 @@ use std::sync::Arc; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio::sync::Mutex; -use crate::Player; - ///! Connect to Minecraft servers. /// Something that can join Minecraft servers. @@ -148,7 +148,7 @@ impl Client { loop { let r = conn.lock().await.read().await; match r { - Ok(packet) => Self::handle(&packet, &tx, &state).await, + Ok(packet) => Self::handle(&packet, &tx, &state, &conn).await, Err(e) => { panic!("Error: {:?}", e); } @@ -160,12 +160,21 @@ impl Client { packet: &GamePacket, tx: &UnboundedSender, state: &Arc>, + conn: &Arc>, ) { match packet { GamePacket::ClientboundLoginPacket(p) => { println!("Got login packet {:?}", p); state.lock().await.player.entity.id = p.player_id; + conn.lock().await.write( + ServerboundCustomPayloadPacket { + identifier: ResourceLocation::new("brand").unwrap(), + // they don't have to know :) + data: "vanilla".into(), + } + .get(), + ); tx.send(Event::Login).unwrap(); } @@ -221,6 +230,7 @@ impl Client { GamePacket::ClientboundAddMobPacket(p) => { println!("Got add mob packet {:?}", p); } + GamePacket::ServerboundCustomPayloadPacket(_) => todo!(), } println!(); } diff --git a/azalea-protocol/packet-macros/src/lib.rs b/azalea-protocol/packet-macros/src/lib.rs index aca7df8c..09a3acb8 100755 --- a/azalea-protocol/packet-macros/src/lib.rs +++ b/azalea-protocol/packet-macros/src/lib.rs @@ -3,13 +3,10 @@ use quote::{quote, ToTokens}; use syn::{ self, braced, parse::{Parse, ParseStream, Result}, - parse_macro_input, DeriveInput, FieldsNamed, Ident, LitInt, Token, + parse_macro_input, Data, DeriveInput, FieldsNamed, Ident, LitInt, Token, }; -#[proc_macro_derive(McBufReadable, attributes(varint))] -pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream { - let DeriveInput { ident, data, .. } = parse_macro_input!(input); - +fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream { let fields = match data { syn::Data::Struct(syn::DataStruct { fields, .. }) => fields, _ => panic!("#[derive(*Packet)] can only be used on structs"), @@ -50,7 +47,6 @@ pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream { quote! { #[async_trait::async_trait] - impl crate::mc_buf::McBufReadable for #ident { async fn read_into(buf: &mut R) -> Result where @@ -63,13 +59,9 @@ pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream { } } } - .into() } -#[proc_macro_derive(McBufWritable, attributes(varint))] -pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream { - let DeriveInput { ident, data, .. } = parse_macro_input!(input); - +fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream { let fields = match data { syn::Data::Struct(syn::DataStruct { fields, .. }) => fields, _ => panic!("#[derive(*Packet)] can only be used on structs"), @@ -115,13 +107,26 @@ pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream { } } } - .into() +} + +#[proc_macro_derive(McBufReadable, attributes(varint))] +pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream { + let DeriveInput { ident, data, .. } = parse_macro_input!(input); + + create_impl_mcbufreadable(&ident, &data).into() +} + +#[proc_macro_derive(McBufWritable, attributes(varint))] +pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream { + let DeriveInput { ident, data, .. } = parse_macro_input!(input); + + create_impl_mcbufwritable(&ident, &data).into() } fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> TokenStream { let DeriveInput { ident, data, .. } = parse_macro_input!(input); - let fields = match data { + let fields = match &data { syn::Data::Struct(syn::DataStruct { fields, .. }) => fields, _ => panic!("#[derive(*Packet)] can only be used on structs"), }; @@ -130,85 +135,33 @@ fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> Toke _ => panic!("#[derive(*Packet)] can only be used on structs with named fields"), }; - let write_fields = named - .iter() - .map(|f| { - let field_name = &f.ident; - let field_type = &f.ty; - // do a different buf.write_* for each field depending on the type - // if it's a string, use buf.write_string - match field_type { - syn::Type::Path(_) => { - if f.attrs.iter().any(|attr| attr.path.is_ident("varint")) { - quote! { - crate::mc_buf::McBufVarintWritable::varint_write_into(&self.#field_name, buf)?; - } - } else { - quote! { - crate::mc_buf::McBufWritable::write_into(&self.#field_name, buf)?; - } - } - } - _ => panic!( - "Error writing field {}: {}", - field_name.clone().unwrap(), - field_type.to_token_stream() - ), - } - }) - .collect::>(); + let mcbufreadable_impl = create_impl_mcbufreadable(&ident, &data); + let mcbufwritable_impl = create_impl_mcbufwritable(&ident, &data); - let read_fields = named - .iter() - .map(|f| { - let field_name = &f.ident; - let field_type = &f.ty; - // do a different buf.write_* for each field depending on the type - // if it's a string, use buf.write_string - match field_type { - syn::Type::Path(_) => { - if f.attrs.iter().any(|a| a.path.is_ident("varint")) { - quote! { - let #field_name = crate::mc_buf::McBufVarintReadable::varint_read_into(buf).await?; - } - } else { - quote! { - let #field_name = crate::mc_buf::McBufReadable::read_into(buf).await?; - } - } - } - _ => panic!( - "Error reading field {}: {}", - field_name.clone().unwrap(), - field_type.to_token_stream() - ), - } - }) - .collect::>(); - let read_field_names = named.iter().map(|f| &f.ident).collect::>(); - - quote! { + let contents = quote! { impl #ident { pub fn get(self) -> #state { #state::#ident(self) } pub fn write(&self, buf: &mut Vec) -> Result<(), std::io::Error> { - #(#write_fields)* - Ok(()) + crate::mc_buf::McBufWritable::write_into(self, buf) } pub async fn read( buf: &mut T, ) -> Result<#state, String> { - #(#read_fields)* - Ok(#ident { - #(#read_field_names: #read_field_names),* - }.get()) + use crate::mc_buf::McBufReadable; + Ok(Self::read_into(buf).await?.get()) } } - } - .into() + + #mcbufreadable_impl + + #mcbufwritable_impl + }; + + contents.into() } #[proc_macro_derive(GamePacket, attributes(varint))] diff --git a/azalea-protocol/src/mc_buf/mod.rs b/azalea-protocol/src/mc_buf/mod.rs index 4048bae7..d50817fb 100755 --- a/azalea-protocol/src/mc_buf/mod.rs +++ b/azalea-protocol/src/mc_buf/mod.rs @@ -32,6 +32,12 @@ impl From> for UnsizedByteArray { } } +impl From<&str> for UnsizedByteArray { + fn from(s: &str) -> Self { + Self(s.as_bytes().to_vec()) + } +} + /// Represents Java's BitSet, a list of bits. #[derive(Debug, Clone, PartialEq, Eq, Hash, McBufReadable, McBufWritable)] pub struct BitSet { diff --git a/azalea-protocol/src/packets/game/mod.rs b/azalea-protocol/src/packets/game/mod.rs index 4b8132f1..aac1a9a0 100755 --- a/azalea-protocol/src/packets/game/mod.rs +++ b/azalea-protocol/src/packets/game/mod.rs @@ -16,12 +16,15 @@ pub mod clientbound_set_chunk_cache_center; pub mod clientbound_update_recipes_packet; pub mod clientbound_update_tags_packet; pub mod clientbound_update_view_distance_packet; +pub mod serverbound_custom_payload_packet; use packet_macros::declare_state_packets; declare_state_packets!( GamePacket, - Serverbound => {}, + Serverbound => { + 0x0a: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket, + }, Clientbound => { 0x02: clientbound_add_mob_packet::ClientboundAddMobPacket, 0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket, diff --git a/azalea-protocol/src/packets/game/serverbound_custom_payload_packet.rs b/azalea-protocol/src/packets/game/serverbound_custom_payload_packet.rs new file mode 100644 index 00000000..43ddb700 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_custom_payload_packet.rs @@ -0,0 +1,11 @@ +// i don't know the actual name of this packet, i couldn't find it in the source code + +use crate::mc_buf::UnsizedByteArray; +use azalea_core::resource_location::ResourceLocation; +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ServerboundCustomPayloadPacket { + pub identifier: ResourceLocation, + pub data: UnsizedByteArray, +}