1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

Reduce usage of AsyncRead

We already receive everything from the server when it tells us the length, so we can actually just treat the stream as a Read instead of an AsyncRead.
This commit is contained in:
mat 2022-05-01 21:54:03 -05:00
parent c2262a2123
commit 567c6f4f2c
29 changed files with 469 additions and 781 deletions

36
Cargo.lock generated
View file

@ -21,9 +21,9 @@ dependencies = [
[[package]] [[package]]
name = "async-compression" name = "async-compression"
version = "0.3.8" version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443ccbb270374a2b1055fc72da40e1f237809cd6bb0e97e66d264cd138473a6" checksum = "f2bf394cfbbe876f0ac67b13b6ca819f9c9f2fb9ec67223cceb1555fbab1c31a"
dependencies = [ dependencies = [
"flate2", "flate2",
"futures-core", "futures-core",
@ -127,14 +127,11 @@ dependencies = [
name = "azalea-nbt" name = "azalea-nbt"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-compression",
"async-recursion",
"byteorder", "byteorder",
"criterion", "criterion",
"flate2", "flate2",
"num-derive", "num-derive",
"num-traits", "num-traits",
"tokio",
] ]
[[package]] [[package]]
@ -143,7 +140,6 @@ version = "0.1.0"
dependencies = [ dependencies = [
"async-compression", "async-compression",
"async-recursion", "async-recursion",
"async-trait",
"azalea-auth", "azalea-auth",
"azalea-brigadier", "azalea-brigadier",
"azalea-chat", "azalea-chat",
@ -152,6 +148,7 @@ dependencies = [
"azalea-nbt", "azalea-nbt",
"byteorder", "byteorder",
"bytes", "bytes",
"flate2",
"num-derive", "num-derive",
"num-traits", "num-traits",
"packet-macros", "packet-macros",
@ -302,7 +299,6 @@ dependencies = [
"clap", "clap",
"criterion-plot", "criterion-plot",
"csv", "csv",
"futures",
"itertools", "itertools",
"lazy_static", "lazy_static",
"num-traits", "num-traits",
@ -315,7 +311,6 @@ dependencies = [
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"tinytemplate", "tinytemplate",
"tokio",
"walkdir", "walkdir",
] ]
@ -441,9 +436,9 @@ dependencies = [
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.22" version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"crc32fast", "crc32fast",
@ -461,20 +456,6 @@ dependencies = [
"percent-encoding", "percent-encoding",
] ]
[[package]]
name = "futures"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.18" version = "0.3.18"
@ -482,7 +463,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink",
] ]
[[package]] [[package]]
@ -516,7 +496,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink",
"futures-task", "futures-task",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
@ -725,12 +704,11 @@ dependencies = [
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.4.4" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082"
dependencies = [ dependencies = [
"adler", "adler",
"autocfg",
] ]
[[package]] [[package]]

View file

@ -135,7 +135,7 @@ impl Client {
let game_loop_conn = conn.clone(); let game_loop_conn = conn.clone();
let game_loop_state = client.state.clone(); let game_loop_state = client.state.clone();
tokio::spawn(async move { Self::game_loop(game_loop_conn, tx, game_loop_state).await }); tokio::spawn(Self::game_loop(game_loop_conn, tx, game_loop_state));
Ok(client) Ok(client)
} }

View file

@ -6,17 +6,13 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
async-compression = {version = "^0.3.8", features = ["tokio", "zlib", "gzip"]} byteorder = "1.4.3"
async-recursion = "^0.3.2" flate2 = "1.0.23"
byteorder = "^1.4.3"
flate2 = "^1.0.22"
num-derive = "^0.3.3" num-derive = "^0.3.3"
num-traits = "^0.2.14" num-traits = "^0.2.14"
tokio = "^1.15.0"
[dev-dependencies] [dev-dependencies]
criterion = {version = "^0.3.5", features = ["html_reports", "async_tokio"]} criterion = {version = "^0.3.5", features = ["html_reports"]}
tokio = {version = "^1.15.0", features = ["fs", "io-util", "macros", "rt", "rt-multi-thread"]}
[profile.release] [profile.release]
lto = true lto = true

View file

@ -19,10 +19,7 @@ fn bench_serialize(filename: &str, c: &mut Criterion) {
let mut decoded_src_stream = std::io::Cursor::new(decoded_src.clone()); let mut decoded_src_stream = std::io::Cursor::new(decoded_src.clone());
file.seek(SeekFrom::Start(0)).unwrap(); file.seek(SeekFrom::Start(0)).unwrap();
// run Tag::read(&mut decoded_src_stream) asynchronously let nbt = Tag::read(&mut decoded_src_stream).unwrap();
let nbt = tokio::runtime::Runtime::new()
.unwrap()
.block_on(async { Tag::read(&mut decoded_src_stream).await.unwrap() });
let mut group = c.benchmark_group(filename); let mut group = c.benchmark_group(filename);

View file

@ -1,64 +1,63 @@
use crate::Error; use crate::Error;
use crate::Tag; use crate::Tag;
use async_compression::tokio::bufread::{GzipDecoder, ZlibDecoder}; use byteorder::{ReadBytesExt, BE};
use async_recursion::async_recursion; use flate2::read::{GzDecoder, ZlibDecoder};
use std::collections::HashMap; use std::collections::HashMap;
use tokio::io::AsyncBufRead; use std::io::BufRead;
use tokio::io::{AsyncRead, AsyncReadExt}; use std::io::Read;
#[inline] #[inline]
async fn read_string<R>(stream: &mut R) -> Result<String, Error> fn read_string<R>(stream: &mut R) -> Result<String, Error>
where where
R: AsyncRead + std::marker::Unpin, R: Read,
{ {
let length = stream.read_u16().await?; let length = stream.read_u16::<BE>()?;
let mut buf = Vec::with_capacity(length as usize); let mut buf = Vec::with_capacity(length as usize);
for _ in 0..length { for _ in 0..length {
buf.push(stream.read_u8().await?); buf.push(stream.read_u8()?);
} }
Ok(String::from_utf8(buf)?) Ok(String::from_utf8(buf)?)
} }
impl Tag { impl Tag {
#[inline] #[inline]
#[async_recursion] fn read_known<R>(stream: &mut R, id: u8) -> Result<Tag, Error>
async fn read_known<R>(stream: &mut R, id: u8) -> Result<Tag, Error>
where where
R: AsyncRead + std::marker::Unpin + std::marker::Send, R: Read,
{ {
let tag = match id { let tag = match id {
// Signifies the end of a TAG_Compound. It is only ever used inside // Signifies the end of a TAG_Compound. It is only ever used inside
// a TAG_Compound, and is not named despite being in a TAG_Compound // a TAG_Compound, and is not named despite being in a TAG_Compound
0 => Tag::End, 0 => Tag::End,
// A single signed byte // A single signed byte
1 => Tag::Byte(stream.read_i8().await?), 1 => Tag::Byte(stream.read_i8()?),
// A single signed, big endian 16 bit integer // A single signed, big endian 16 bit integer
2 => Tag::Short(stream.read_i16().await?), 2 => Tag::Short(stream.read_i16::<BE>()?),
// A single signed, big endian 32 bit integer // A single signed, big endian 32 bit integer
3 => Tag::Int(stream.read_i32().await?), 3 => Tag::Int(stream.read_i32::<BE>()?),
// A single signed, big endian 64 bit integer // A single signed, big endian 64 bit integer
4 => Tag::Long(stream.read_i64().await?), 4 => Tag::Long(stream.read_i64::<BE>()?),
// A single, big endian IEEE-754 single-precision floating point // A single, big endian IEEE-754 single-precision floating point
// number (NaN possible) // number (NaN possible)
5 => Tag::Float(stream.read_f32().await?), 5 => Tag::Float(stream.read_f32::<BE>()?),
// A single, big endian IEEE-754 double-precision floating point // A single, big endian IEEE-754 double-precision floating point
// number (NaN possible) // number (NaN possible)
6 => Tag::Double(stream.read_f64().await?), 6 => Tag::Double(stream.read_f64::<BE>()?),
// A length-prefixed array of signed bytes. The prefix is a signed // A length-prefixed array of signed bytes. The prefix is a signed
// integer (thus 4 bytes) // integer (thus 4 bytes)
7 => { 7 => {
let length = stream.read_i32().await?; let length = stream.read_i32::<BE>()?;
let mut bytes = Vec::with_capacity(length as usize); let mut bytes = Vec::with_capacity(length as usize);
for _ in 0..length { for _ in 0..length {
bytes.push(stream.read_i8().await?); bytes.push(stream.read_i8()?);
} }
Tag::ByteArray(bytes) Tag::ByteArray(bytes)
} }
// A length-prefixed modified UTF-8 string. The prefix is an // A length-prefixed modified UTF-8 string. The prefix is an
// unsigned short (thus 2 bytes) signifying the length of the // unsigned short (thus 2 bytes) signifying the length of the
// string in bytes // string in bytes
8 => Tag::String(read_string(stream).await?), 8 => Tag::String(read_string(stream)?),
// A list of nameless tags, all of the same type. The list is // A list of nameless tags, all of the same type. The list is
// prefixed with the Type ID of the items it contains (thus 1 // prefixed with the Type ID of the items it contains (thus 1
// byte), and the length of the list as a signed integer (a further // byte), and the length of the list as a signed integer (a further
@ -68,11 +67,11 @@ impl Tag {
// another reference implementation by Mojang uses 1 instead; // another reference implementation by Mojang uses 1 instead;
// parsers should accept any type if the length is <= 0). // parsers should accept any type if the length is <= 0).
9 => { 9 => {
let type_id = stream.read_u8().await?; let type_id = stream.read_u8()?;
let length = stream.read_i32().await?; let length = stream.read_i32::<BE>()?;
let mut list = Vec::with_capacity(length as usize); let mut list = Vec::with_capacity(length as usize);
for _ in 0..length { for _ in 0..length {
list.push(Tag::read_known(stream, type_id).await?); list.push(Tag::read_known(stream, type_id)?);
} }
Tag::List(list) Tag::List(list)
} }
@ -81,12 +80,12 @@ impl Tag {
// we default to capacity 4 because it'll probably not be empty // we default to capacity 4 because it'll probably not be empty
let mut map = HashMap::with_capacity(4); let mut map = HashMap::with_capacity(4);
loop { loop {
let tag_id = stream.read_u8().await.unwrap_or(0); let tag_id = stream.read_u8().unwrap_or(0);
if tag_id == 0 { if tag_id == 0 {
break; break;
} }
let name = read_string(stream).await?; let name = read_string(stream)?;
let tag = Tag::read_known(stream, tag_id).await?; let tag = Tag::read_known(stream, tag_id)?;
map.insert(name, tag); map.insert(name, tag);
} }
Tag::Compound(map) Tag::Compound(map)
@ -95,20 +94,20 @@ impl Tag {
// signed integer (thus 4 bytes) and indicates the number of 4 byte // signed integer (thus 4 bytes) and indicates the number of 4 byte
// integers. // integers.
11 => { 11 => {
let length = stream.read_i32().await?; let length = stream.read_i32::<BE>()?;
let mut ints = Vec::with_capacity(length as usize); let mut ints = Vec::with_capacity(length as usize);
for _ in 0..length { for _ in 0..length {
ints.push(stream.read_i32().await?); ints.push(stream.read_i32::<BE>()?);
} }
Tag::IntArray(ints) Tag::IntArray(ints)
} }
// A length-prefixed array of signed longs. The prefix is a signed // A length-prefixed array of signed longs. The prefix is a signed
// integer (thus 4 bytes) and indicates the number of 8 byte longs. // integer (thus 4 bytes) and indicates the number of 8 byte longs.
12 => { 12 => {
let length = stream.read_i32().await?; let length = stream.read_i32::<BE>()?;
let mut longs = Vec::with_capacity(length as usize); let mut longs = Vec::with_capacity(length as usize);
for _ in 0..length { for _ in 0..length {
longs.push(stream.read_i64().await?); longs.push(stream.read_i64::<BE>()?);
} }
Tag::LongArray(longs) Tag::LongArray(longs)
} }
@ -117,38 +116,38 @@ impl Tag {
Ok(tag) Ok(tag)
} }
pub async fn read<R>(stream: &mut R) -> Result<Tag, Error> pub fn read<R>(stream: &mut R) -> Result<Tag, Error>
where where
R: AsyncRead + std::marker::Unpin + std::marker::Send, R: Read,
{ {
// default to compound tag // default to compound tag
// the parent compound only ever has one item // the parent compound only ever has one item
let tag_id = stream.read_u8().await.unwrap_or(0); let tag_id = stream.read_u8().unwrap_or(0);
if tag_id == 0 { if tag_id == 0 {
return Ok(Tag::End); return Ok(Tag::End);
} }
let name = read_string(stream).await?; let name = read_string(stream)?;
let tag = Tag::read_known(stream, tag_id).await?; let tag = Tag::read_known(stream, tag_id)?;
let mut map = HashMap::with_capacity(1); let mut map = HashMap::with_capacity(1);
map.insert(name, tag); map.insert(name, tag);
Ok(Tag::Compound(map)) Ok(Tag::Compound(map))
} }
pub async fn read_zlib<R>(stream: &mut R) -> Result<Tag, Error> pub fn read_zlib<R>(stream: &mut R) -> Result<Tag, Error>
where where
R: AsyncBufRead + std::marker::Unpin + std::marker::Send, R: BufRead,
{ {
let mut gz = ZlibDecoder::new(stream); let mut gz = ZlibDecoder::new(stream);
Tag::read(&mut gz).await Tag::read(&mut gz)
} }
pub async fn read_gzip<R>(stream: &mut R) -> Result<Tag, Error> pub fn read_gzip<R>(stream: &mut R) -> Result<Tag, Error>
where where
R: AsyncBufRead + std::marker::Unpin + std::marker::Send, R: Read,
{ {
let mut gz = GzipDecoder::new(stream); let mut gz = GzDecoder::new(stream);
Tag::read(&mut gz).await Tag::read(&mut gz)
} }
} }

View file

@ -1,15 +1,15 @@
use azalea_nbt::Tag; use azalea_nbt::Tag;
use std::{ use std::{
collections::HashMap, collections::HashMap,
fs::File,
io::{Cursor, Read}, io::{Cursor, Read},
}; };
use tokio::{fs::File, io::AsyncReadExt};
#[tokio::test] #[test]
async fn test_decode_hello_world() { fn test_decode_hello_world() {
// read hello_world.nbt // read hello_world.nbt
let mut file = File::open("tests/hello_world.nbt").await.unwrap(); let mut file = File::open("tests/hello_world.nbt").unwrap();
let tag = Tag::read(&mut file).await.unwrap(); let tag = Tag::read(&mut file).unwrap();
assert_eq!( assert_eq!(
tag, tag,
Tag::Compound(HashMap::from_iter(vec![( Tag::Compound(HashMap::from_iter(vec![(
@ -22,14 +22,14 @@ async fn test_decode_hello_world() {
); );
} }
#[tokio::test] #[test]
async fn test_roundtrip_hello_world() { fn test_roundtrip_hello_world() {
let mut file = File::open("tests/hello_world.nbt").await.unwrap(); let mut file = File::open("tests/hello_world.nbt").unwrap();
let mut original = Vec::new(); let mut original = Vec::new();
file.read_to_end(&mut original).await.unwrap(); file.read_to_end(&mut original).unwrap();
let mut original_stream = Cursor::new(original.clone()); let mut original_stream = Cursor::new(original.clone());
let tag = Tag::read(&mut original_stream).await.unwrap(); let tag = Tag::read(&mut original_stream).unwrap();
// write hello_world.nbt // write hello_world.nbt
let mut result = Cursor::new(Vec::new()); let mut result = Cursor::new(Vec::new());
@ -38,26 +38,26 @@ async fn test_roundtrip_hello_world() {
assert_eq!(result.into_inner(), original); assert_eq!(result.into_inner(), original);
} }
#[tokio::test] #[test]
async fn test_bigtest() { fn test_bigtest() {
// read bigtest.nbt // read bigtest.nbt
let mut file = File::open("tests/bigtest.nbt").await.unwrap(); let mut file = File::open("tests/bigtest.nbt").unwrap();
let mut original = Vec::new(); let mut original = Vec::new();
file.read_to_end(&mut original).await.unwrap(); file.read_to_end(&mut original).unwrap();
let mut original_stream = Cursor::new(original.clone()); let mut original_stream = Cursor::new(original.clone());
let original_tag = Tag::read_gzip(&mut original_stream).await.unwrap(); let original_tag = Tag::read_gzip(&mut original_stream).unwrap();
let mut result = Vec::new(); let mut result = Vec::new();
original_tag.write(&mut result).unwrap(); original_tag.write(&mut result).unwrap();
let decoded_tag = Tag::read(&mut Cursor::new(result)).await.unwrap(); let decoded_tag = Tag::read(&mut Cursor::new(result)).unwrap();
assert_eq!(decoded_tag, original_tag); assert_eq!(decoded_tag, original_tag);
} }
#[tokio::test] #[test]
async fn test_stringtest() { fn test_stringtest() {
let correct_tag = Tag::Compound(HashMap::from_iter(vec![( let correct_tag = Tag::Compound(HashMap::from_iter(vec![(
"😃".to_string(), "😃".to_string(),
Tag::List(vec![ Tag::List(vec![
@ -84,41 +84,41 @@ async fn test_stringtest() {
file.read_to_end(&mut original).unwrap(); file.read_to_end(&mut original).unwrap();
let mut original_stream = Cursor::new(original.clone()); let mut original_stream = Cursor::new(original.clone());
let original_tag = Tag::read_gzip(&mut original_stream).await.unwrap(); let original_tag = Tag::read_gzip(&mut original_stream).unwrap();
assert_eq!(original_tag, correct_tag); assert_eq!(original_tag, correct_tag);
} }
#[tokio::test] #[test]
async fn test_complex_player() { fn test_complex_player() {
let mut file = File::open("tests/complex_player.dat").await.unwrap(); let mut file = File::open("tests/complex_player.dat").unwrap();
let mut original = Vec::new(); let mut original = Vec::new();
file.read_to_end(&mut original).await.unwrap(); file.read_to_end(&mut original).unwrap();
let mut original_stream = Cursor::new(original.clone()); let mut original_stream = Cursor::new(original.clone());
let original_tag = Tag::read_gzip(&mut original_stream).await.unwrap(); let original_tag = Tag::read_gzip(&mut original_stream).unwrap();
let mut result = Vec::new(); let mut result = Vec::new();
original_tag.write(&mut result).unwrap(); original_tag.write(&mut result).unwrap();
let decoded_tag = Tag::read(&mut Cursor::new(result)).await.unwrap(); let decoded_tag = Tag::read(&mut Cursor::new(result)).unwrap();
assert_eq!(decoded_tag, original_tag); assert_eq!(decoded_tag, original_tag);
} }
#[tokio::test] #[test]
async fn test_simple_player() { fn test_simple_player() {
let mut file = File::open("tests/simple_player.dat").await.unwrap(); let mut file = File::open("tests/simple_player.dat").unwrap();
let mut original = Vec::new(); let mut original = Vec::new();
file.read_to_end(&mut original).await.unwrap(); file.read_to_end(&mut original).unwrap();
let mut original_stream = Cursor::new(original.clone()); let mut original_stream = Cursor::new(original.clone());
let original_tag = Tag::read_gzip(&mut original_stream).await.unwrap(); let original_tag = Tag::read_gzip(&mut original_stream).unwrap();
let mut result = Vec::new(); let mut result = Vec::new();
original_tag.write(&mut result).unwrap(); original_tag.write(&mut result).unwrap();
let decoded_tag = Tag::read(&mut Cursor::new(result)).await.unwrap(); let decoded_tag = Tag::read(&mut Cursor::new(result)).unwrap();
assert_eq!(decoded_tag, original_tag); assert_eq!(decoded_tag, original_tag);
} }

View file

@ -8,7 +8,6 @@ version = "0.1.0"
[dependencies] [dependencies]
async-compression = {version = "^0.3.8", features = ["tokio", "zlib"]} async-compression = {version = "^0.3.8", features = ["tokio", "zlib"]}
async-recursion = "^0.3.2" async-recursion = "^0.3.2"
async-trait = "0.1.51"
azalea-auth = {path = "../azalea-auth"} azalea-auth = {path = "../azalea-auth"}
azalea-brigadier = {path = "../azalea-brigadier"} azalea-brigadier = {path = "../azalea-brigadier"}
azalea-chat = {path = "../azalea-chat"} azalea-chat = {path = "../azalea-chat"}
@ -17,6 +16,7 @@ azalea-crypto = {path = "../azalea-crypto"}
azalea-nbt = {path = "../azalea-nbt"} azalea-nbt = {path = "../azalea-nbt"}
byteorder = "^1.4.3" byteorder = "^1.4.3"
bytes = "^1.1.0" bytes = "^1.1.0"
flate2 = "1.0.23"
num-derive = "^0.3.3" num-derive = "^0.3.3"
num-traits = "^0.2.14" num-traits = "^0.2.14"
packet-macros = {path = "./packet-macros"} packet-macros = {path = "./packet-macros"}

View file

@ -25,11 +25,11 @@ fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenSt
syn::Type::Path(_) => { syn::Type::Path(_) => {
if f.attrs.iter().any(|a| a.path.is_ident("varint")) { if f.attrs.iter().any(|a| a.path.is_ident("varint")) {
quote! { quote! {
let #field_name = crate::mc_buf::McBufVarintReadable::varint_read_into(buf).await?; let #field_name = crate::mc_buf::McBufVarintReadable::varint_read_into(buf)?;
} }
} else { } else {
quote! { quote! {
let #field_name = crate::mc_buf::McBufReadable::read_into(buf).await?; let #field_name = crate::mc_buf::McBufReadable::read_into(buf)?;
} }
} }
} }
@ -44,12 +44,8 @@ fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenSt
let read_field_names = named.iter().map(|f| &f.ident).collect::<Vec<_>>(); let read_field_names = named.iter().map(|f| &f.ident).collect::<Vec<_>>();
quote! { quote! {
#[async_trait::async_trait]
impl crate::mc_buf::McBufReadable for #ident { impl crate::mc_buf::McBufReadable for #ident {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl std::io::Read) -> Result<Self, String> {
where
R: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send,
{
#(#read_fields)* #(#read_fields)*
Ok(#ident { Ok(#ident {
#(#read_field_names: #read_field_names),* #(#read_field_names: #read_field_names),*
@ -73,13 +69,10 @@ fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenSt
} }
quote! { quote! {
#[async_trait::async_trait]
impl crate::mc_buf::McBufReadable for #ident { impl crate::mc_buf::McBufReadable for #ident {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl std::io::Read) -> Result<Self, String>
where
R: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send,
{ {
let id = buf.read_varint().await?; let id = buf.read_varint()?;
match id { match id {
#match_contents #match_contents
_ => Err(format!("Unknown enum variant {}", id)), _ => Err(format!("Unknown enum variant {}", id)),
@ -189,11 +182,11 @@ fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> Toke
crate::mc_buf::McBufWritable::write_into(self, buf) crate::mc_buf::McBufWritable::write_into(self, buf)
} }
pub async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>( pub fn read(
buf: &mut T, buf: &mut impl std::io::Read,
) -> Result<#state, String> { ) -> Result<#state, String> {
use crate::mc_buf::McBufReadable; use crate::mc_buf::McBufReadable;
Ok(Self::read_into(buf).await?.get()) Ok(Self::read_into(buf)?.get())
} }
} }
@ -339,7 +332,7 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
#state_name::#name(packet) => packet.write(buf), #state_name::#name(packet) => packet.write(buf),
}); });
serverbound_read_match_contents.extend(quote! { serverbound_read_match_contents.extend(quote! {
#id => #module::#name::read(buf).await?, #id => #module::#name::read(buf)?,
}); });
} }
for PacketIdPair { id, module, name } in input.clientbound.packets { for PacketIdPair { id, module, name } in input.clientbound.packets {
@ -353,7 +346,7 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
#state_name::#name(packet) => packet.write(buf), #state_name::#name(packet) => packet.write(buf),
}); });
clientbound_read_match_contents.extend(quote! { clientbound_read_match_contents.extend(quote! {
#id => #module::#name::read(buf).await?, #id => #module::#name::read(buf)?,
}); });
} }
@ -366,7 +359,6 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
#enum_contents #enum_contents
} }
#[async_trait::async_trait]
impl crate::packets::ProtocolPacket for #state_name { impl crate::packets::ProtocolPacket for #state_name {
fn id(&self) -> u32 { fn id(&self) -> u32 {
match self { match self {
@ -381,10 +373,10 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
} }
/// Read a packet by its id, ConnectionProtocol, and flow /// Read a packet by its id, ConnectionProtocol, and flow
async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>( fn read(
id: u32, id: u32,
flow: &crate::connect::PacketFlow, flow: &crate::connect::PacketFlow,
buf: &mut T, buf: &mut impl std::io::Read,
) -> Result<#state_name, String> ) -> Result<#state_name, String>
where where
Self: Sized, Self: Sized,

View file

@ -4,7 +4,7 @@ mod read;
mod write; mod write;
use packet_macros::{McBufReadable, McBufWritable}; use packet_macros::{McBufReadable, McBufWritable};
pub use read::{McBufReadable, McBufVarintReadable, Readable}; pub use read::{read_varint_async, McBufReadable, McBufVarintReadable, Readable};
use std::ops::{Deref, Index}; use std::ops::{Deref, Index};
pub use write::{McBufVarintWritable, McBufWritable, Writable}; pub use write::{McBufVarintWritable, McBufWritable, Writable};
@ -56,7 +56,6 @@ mod tests {
use super::*; use super::*;
use azalea_core::resource_location::ResourceLocation; use azalea_core::resource_location::ResourceLocation;
use std::{collections::HashMap, io::Cursor}; use std::{collections::HashMap, io::Cursor};
use tokio::io::BufReader;
#[test] #[test]
fn test_write_varint() { fn test_write_varint() {
@ -105,91 +104,91 @@ mod tests {
assert_eq!(buf, vec![128, 128, 128, 128, 8]); assert_eq!(buf, vec![128, 128, 128, 128, 8]);
} }
#[tokio::test] #[test]
async fn test_read_varint() { fn test_read_varint() {
let mut buf = BufReader::new(Cursor::new(vec![0])); let mut buf = Cursor::new(vec![0]);
assert_eq!(buf.read_varint().await.unwrap(), 0); assert_eq!(buf.read_varint().unwrap(), 0);
assert_eq!(buf.get_varint_size(0), 1); assert_eq!(buf.get_varint_size(0), 1);
let mut buf = BufReader::new(Cursor::new(vec![1])); let mut buf = Cursor::new(vec![1]);
assert_eq!(buf.read_varint().await.unwrap(), 1); assert_eq!(buf.read_varint().unwrap(), 1);
assert_eq!(buf.get_varint_size(1), 1); assert_eq!(buf.get_varint_size(1), 1);
let mut buf = BufReader::new(Cursor::new(vec![2])); let mut buf = Cursor::new(vec![2]);
assert_eq!(buf.read_varint().await.unwrap(), 2); assert_eq!(buf.read_varint().unwrap(), 2);
assert_eq!(buf.get_varint_size(2), 1); assert_eq!(buf.get_varint_size(2), 1);
let mut buf = BufReader::new(Cursor::new(vec![127])); let mut buf = Cursor::new(vec![127]);
assert_eq!(buf.read_varint().await.unwrap(), 127); assert_eq!(buf.read_varint().unwrap(), 127);
assert_eq!(buf.get_varint_size(127), 1); assert_eq!(buf.get_varint_size(127), 1);
let mut buf = BufReader::new(Cursor::new(vec![128, 1])); let mut buf = Cursor::new(vec![128, 1]);
assert_eq!(buf.read_varint().await.unwrap(), 128); assert_eq!(buf.read_varint().unwrap(), 128);
assert_eq!(buf.get_varint_size(128), 2); assert_eq!(buf.get_varint_size(128), 2);
let mut buf = BufReader::new(Cursor::new(vec![255, 1])); let mut buf = Cursor::new(vec![255, 1]);
assert_eq!(buf.read_varint().await.unwrap(), 255); assert_eq!(buf.read_varint().unwrap(), 255);
assert_eq!(buf.get_varint_size(255), 2); assert_eq!(buf.get_varint_size(255), 2);
let mut buf = BufReader::new(Cursor::new(vec![221, 199, 1])); let mut buf = Cursor::new(vec![221, 199, 1]);
assert_eq!(buf.read_varint().await.unwrap(), 25565); assert_eq!(buf.read_varint().unwrap(), 25565);
assert_eq!(buf.get_varint_size(25565), 3); assert_eq!(buf.get_varint_size(25565), 3);
let mut buf = BufReader::new(Cursor::new(vec![255, 255, 127])); let mut buf = Cursor::new(vec![255, 255, 127]);
assert_eq!(buf.read_varint().await.unwrap(), 2097151); assert_eq!(buf.read_varint().unwrap(), 2097151);
assert_eq!(buf.get_varint_size(2097151), 3); assert_eq!(buf.get_varint_size(2097151), 3);
let mut buf = BufReader::new(Cursor::new(vec![255, 255, 255, 255, 7])); let mut buf = Cursor::new(vec![255, 255, 255, 255, 7]);
assert_eq!(buf.read_varint().await.unwrap(), 2147483647); assert_eq!(buf.read_varint().unwrap(), 2147483647);
assert_eq!(buf.get_varint_size(2147483647), 5); assert_eq!(buf.get_varint_size(2147483647), 5);
let mut buf = BufReader::new(Cursor::new(vec![255, 255, 255, 255, 15])); let mut buf = Cursor::new(vec![255, 255, 255, 255, 15]);
assert_eq!(buf.read_varint().await.unwrap(), -1); assert_eq!(buf.read_varint().unwrap(), -1);
assert_eq!(buf.get_varint_size(-1), 5); assert_eq!(buf.get_varint_size(-1), 5);
let mut buf = BufReader::new(Cursor::new(vec![128, 128, 128, 128, 8])); let mut buf = Cursor::new(vec![128, 128, 128, 128, 8]);
assert_eq!(buf.read_varint().await.unwrap(), -2147483648); assert_eq!(buf.read_varint().unwrap(), -2147483648);
assert_eq!(buf.get_varint_size(-2147483648), 5); assert_eq!(buf.get_varint_size(-2147483648), 5);
} }
#[tokio::test] #[test]
async fn test_read_varint_longer() { fn test_read_varint_longer() {
let mut buf = BufReader::new(Cursor::new(vec![138, 56, 0, 135, 56, 123])); let mut buf = Cursor::new(vec![138, 56, 0, 135, 56, 123]);
assert_eq!(buf.read_varint().await.unwrap(), 7178); assert_eq!(buf.read_varint().unwrap(), 7178);
} }
#[tokio::test] #[test]
async fn test_list() { fn test_list() {
let mut buf = Vec::new(); let mut buf = Vec::new();
buf.write_list(&vec!["a", "bc", "def"], |buf, s| buf.write_utf(s)) buf.write_list(&vec!["a", "bc", "def"], |buf, s| buf.write_utf(s))
.unwrap(); .unwrap();
// there's no read_list because idk how to do it in rust // there's no read_list because idk how to do it in rust
let mut buf = BufReader::new(Cursor::new(buf)); let mut buf = Cursor::new(buf);
let mut result = Vec::new(); let mut result = Vec::new();
let length = buf.read_varint().await.unwrap(); let length = buf.read_varint().unwrap();
for _ in 0..length { for _ in 0..length {
result.push(buf.read_utf().await.unwrap()); result.push(buf.read_utf().unwrap());
} }
assert_eq!(result, vec!["a", "bc", "def"]); assert_eq!(result, vec!["a", "bc", "def"]);
} }
#[tokio::test] #[test]
async fn test_int_id_list() { fn test_int_id_list() {
let mut buf = Vec::new(); let mut buf = Vec::new();
buf.write_list(&vec![1, 2, 3], |buf, i| buf.write_varint(*i)) buf.write_list(&vec![1, 2, 3], |buf, i| buf.write_varint(*i))
.unwrap(); .unwrap();
let mut buf = BufReader::new(Cursor::new(buf)); let mut buf = Cursor::new(buf);
let result = buf.read_int_id_list().await.unwrap(); let result = buf.read_int_id_list().unwrap();
assert_eq!(result, vec![1, 2, 3]); assert_eq!(result, vec![1, 2, 3]);
} }
#[tokio::test] #[test]
async fn test_map() { fn test_map() {
let mut buf = Vec::new(); let mut buf = Vec::new();
buf.write_map( buf.write_map(
vec![("a", 1), ("bc", 23), ("def", 456)], vec![("a", 1), ("bc", 23), ("def", 456)],
@ -198,15 +197,12 @@ mod tests {
) )
.unwrap(); .unwrap();
let mut buf = BufReader::new(Cursor::new(buf)); let mut buf = Cursor::new(buf);
let mut result = Vec::new(); let mut result = Vec::new();
let length = buf.read_varint().await.unwrap(); let length = buf.read_varint().unwrap();
for _ in 0..length { for _ in 0..length {
result.push(( result.push((buf.read_utf().unwrap(), buf.read_varint().unwrap()));
buf.read_utf().await.unwrap(),
buf.read_varint().await.unwrap(),
));
} }
assert_eq!( assert_eq!(
@ -219,8 +215,8 @@ mod tests {
); );
} }
#[tokio::test] #[test]
async fn test_nbt() { fn test_nbt() {
let mut buf = Vec::new(); let mut buf = Vec::new();
buf.write_nbt(&azalea_nbt::Tag::Compound(HashMap::from_iter(vec![( buf.write_nbt(&azalea_nbt::Tag::Compound(HashMap::from_iter(vec![(
"hello world".to_string(), "hello world".to_string(),
@ -231,9 +227,9 @@ mod tests {
)]))) )])))
.unwrap(); .unwrap();
let mut buf = BufReader::new(Cursor::new(buf)); let mut buf = Cursor::new(buf);
let result = buf.read_nbt().await.unwrap(); let result = buf.read_nbt().unwrap();
assert_eq!( assert_eq!(
result, result,
azalea_nbt::Tag::Compound(HashMap::from_iter(vec![( azalea_nbt::Tag::Compound(HashMap::from_iter(vec![(
@ -246,26 +242,26 @@ mod tests {
); );
} }
#[tokio::test] #[test]
async fn test_long() { fn test_long() {
let mut buf = Vec::new(); let mut buf = Vec::new();
buf.write_long(123456).unwrap(); buf.write_long(123456).unwrap();
let mut buf = BufReader::new(Cursor::new(buf)); let mut buf = Cursor::new(buf);
assert_eq!(buf.read_long().await.unwrap(), 123456); assert_eq!(buf.read_long().unwrap(), 123456);
} }
#[tokio::test] #[test]
async fn test_resource_location() { fn test_resource_location() {
let mut buf = Vec::new(); let mut buf = Vec::new();
buf.write_resource_location(&ResourceLocation::new("minecraft:dirt").unwrap()) buf.write_resource_location(&ResourceLocation::new("minecraft:dirt").unwrap())
.unwrap(); .unwrap();
let mut buf = BufReader::new(Cursor::new(buf)); let mut buf = Cursor::new(buf);
assert_eq!( assert_eq!(
buf.read_resource_location().await.unwrap(), buf.read_resource_location().unwrap(),
ResourceLocation::new("minecraft:dirt").unwrap() ResourceLocation::new("minecraft:dirt").unwrap()
); );
} }

View file

@ -1,60 +1,57 @@
use async_trait::async_trait; use super::{BitSet, UnsizedByteArray, MAX_STRING_LENGTH};
use azalea_chat::component::Component; use azalea_chat::component::Component;
use azalea_core::{ use azalea_core::{
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation, difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
serializable_uuid::SerializableUuid, BlockPos, Direction, Slot, SlotData, serializable_uuid::SerializableUuid, BlockPos, Direction, Slot, SlotData,
}; };
use byteorder::{ReadBytesExt, WriteBytesExt, BE};
use serde::Deserialize; use serde::Deserialize;
use std::io::Read;
use tokio::io::{AsyncRead, AsyncReadExt}; use tokio::io::{AsyncRead, AsyncReadExt};
use uuid::Uuid; use uuid::Uuid;
use super::{BitSet, UnsizedByteArray, MAX_STRING_LENGTH};
#[async_trait]
pub trait Readable { pub trait Readable {
async fn read_int_id_list(&mut self) -> Result<Vec<i32>, String>; fn read_int_id_list(&mut self) -> Result<Vec<i32>, String>;
async fn read_varint(&mut self) -> Result<i32, String>; fn read_varint(&mut self) -> Result<i32, String>;
fn get_varint_size(&mut self, value: i32) -> u8; fn get_varint_size(&mut self, value: i32) -> u8;
fn get_varlong_size(&mut self, value: i32) -> u8; fn get_varlong_size(&mut self, value: i32) -> u8;
async fn read_byte_array(&mut self) -> Result<Vec<u8>, String>; fn read_byte_array(&mut self) -> Result<Vec<u8>, String>;
async fn read_bytes_with_len(&mut self, n: usize) -> Result<Vec<u8>, String>; fn read_bytes_with_len(&mut self, n: usize) -> Result<Vec<u8>, String>;
async fn read_bytes(&mut self) -> Result<Vec<u8>, String>; fn read_bytes(&mut self) -> Result<Vec<u8>, String>;
async fn read_utf(&mut self) -> Result<String, String>; fn read_utf(&mut self) -> Result<String, String>;
async fn read_utf_with_len(&mut self, max_length: u32) -> Result<String, String>; fn read_utf_with_len(&mut self, max_length: u32) -> Result<String, String>;
async fn read_byte(&mut self) -> Result<u8, String>; fn read_byte(&mut self) -> Result<u8, String>;
async fn read_int(&mut self) -> Result<i32, String>; fn read_int(&mut self) -> Result<i32, String>;
async fn read_boolean(&mut self) -> Result<bool, String>; fn read_boolean(&mut self) -> Result<bool, String>;
async fn read_nbt(&mut self) -> Result<azalea_nbt::Tag, String>; fn read_nbt(&mut self) -> Result<azalea_nbt::Tag, String>;
async fn read_long(&mut self) -> Result<i64, String>; fn read_long(&mut self) -> Result<i64, String>;
async fn read_resource_location(&mut self) -> Result<ResourceLocation, String>; fn read_resource_location(&mut self) -> Result<ResourceLocation, String>;
async fn read_short(&mut self) -> Result<i16, String>; fn read_short(&mut self) -> Result<i16, String>;
async fn read_float(&mut self) -> Result<f32, String>; fn read_float(&mut self) -> Result<f32, String>;
async fn read_double(&mut self) -> Result<f64, String>; fn read_double(&mut self) -> Result<f64, String>;
async fn read_uuid(&mut self) -> Result<Uuid, String>; fn read_uuid(&mut self) -> Result<Uuid, String>;
} }
#[async_trait]
impl<R> Readable for R impl<R> Readable for R
where where
R: AsyncRead + std::marker::Unpin + std::marker::Send, R: Read,
{ {
async fn read_int_id_list(&mut self) -> Result<Vec<i32>, String> { fn read_int_id_list(&mut self) -> Result<Vec<i32>, String> {
let len = self.read_varint().await?; let len = self.read_varint()?;
let mut list = Vec::with_capacity(len as usize); let mut list = Vec::with_capacity(len as usize);
for _ in 0..len { for _ in 0..len {
list.push(self.read_varint().await?); list.push(self.read_varint()?);
} }
Ok(list) Ok(list)
} }
// fast varints modified 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 /// 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<i32, String> { fn read_varint(&mut self) -> Result<i32, String> {
let mut buffer = [0]; let mut buffer = [0];
let mut ans = 0; let mut ans = 0;
for i in 0..5 { for i in 0..5 {
self.read_exact(&mut buffer) self.read_exact(&mut buffer)
.await
.map_err(|_| "Invalid VarInt".to_string())?; .map_err(|_| "Invalid VarInt".to_string())?;
ans |= ((buffer[0] & 0b0111_1111) as i32) << (7 * i); ans |= ((buffer[0] & 0b0111_1111) as i32) << (7 * i);
if buffer[0] & 0b1000_0000 == 0 { if buffer[0] & 0b1000_0000 == 0 {
@ -84,34 +81,32 @@ where
10 10
} }
async fn read_byte_array(&mut self) -> Result<Vec<u8>, String> { fn read_byte_array(&mut self) -> Result<Vec<u8>, String> {
let length = self.read_varint().await? as usize; let length = self.read_varint()? as usize;
self.read_bytes_with_len(length).await self.read_bytes_with_len(length)
} }
async fn read_bytes_with_len(&mut self, n: usize) -> Result<Vec<u8>, String> { fn read_bytes_with_len(&mut self, n: usize) -> Result<Vec<u8>, String> {
let mut bytes = vec![0; n]; let mut buffer = vec![0; n];
match AsyncReadExt::read_exact(self, &mut bytes).await { self.read_exact(&mut buffer)
Ok(_) => Ok(bytes), .map_err(|_| "Error reading bytes".to_string())?;
Err(_) => Err("Error reading bytes".to_string()), Ok(buffer)
}
} }
async fn read_bytes(&mut self) -> Result<Vec<u8>, String> { fn read_bytes(&mut self) -> Result<Vec<u8>, String> {
// read to end of the buffer // read to end of the buffer
let mut bytes = vec![]; let mut bytes = vec![];
AsyncReadExt::read_to_end(self, &mut bytes) self.read_to_end(&mut bytes)
.await
.map_err(|_| "Error reading bytes".to_string())?; .map_err(|_| "Error reading bytes".to_string())?;
Ok(bytes) Ok(bytes)
} }
async fn read_utf(&mut self) -> Result<String, String> { fn read_utf(&mut self) -> Result<String, String> {
self.read_utf_with_len(MAX_STRING_LENGTH.into()).await self.read_utf_with_len(MAX_STRING_LENGTH.into())
} }
async fn read_utf_with_len(&mut self, max_length: u32) -> Result<String, String> { fn read_utf_with_len(&mut self, max_length: u32) -> Result<String, String> {
let length = self.read_varint().await?; let length = self.read_varint()?;
// i don't know why it's multiplied by 4 but it's like that in mojang's code so // i don't know why it's multiplied by 4 but it's like that in mojang's code so
if length < 0 { if length < 0 {
return Err( return Err(
@ -131,7 +126,6 @@ where
let mut string = String::new(); let mut string = String::new();
let mut buffer = vec![0; length as usize]; let mut buffer = vec![0; length as usize];
self.read_exact(&mut buffer) self.read_exact(&mut buffer)
.await
.map_err(|_| "Invalid UTF-8".to_string())?; .map_err(|_| "Invalid UTF-8".to_string())?;
string.push_str(std::str::from_utf8(&buffer).unwrap()); string.push_str(std::str::from_utf8(&buffer).unwrap());
if string.len() > length as usize { if string.len() > length as usize {
@ -145,342 +139,263 @@ where
} }
/// Read a single byte from the reader /// Read a single byte from the reader
async fn read_byte(&mut self) -> Result<u8, String> { fn read_byte(&mut self) -> Result<u8, String> {
match AsyncReadExt::read_u8(self).await { self.read_u8().map_err(|_| "Error reading byte".to_string())
Ok(r) => Ok(r),
Err(_) => Err("Error reading byte".to_string()),
}
} }
async fn read_int(&mut self) -> Result<i32, String> { fn read_int(&mut self) -> Result<i32, String> {
match AsyncReadExt::read_i32(self).await { match self.read_i32::<BE>() {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(_) => Err("Error reading int".to_string()), Err(_) => Err("Error reading int".to_string()),
} }
} }
async fn read_boolean(&mut self) -> Result<bool, String> { fn read_boolean(&mut self) -> Result<bool, String> {
match self.read_byte().await { match self.read_byte()? {
Ok(0) => Ok(false), 0 => Ok(false),
Ok(1) => Ok(true), 1 => Ok(true),
_ => Err("Error reading boolean".to_string()), _ => Err("Error reading boolean".to_string()),
} }
} }
async fn read_nbt(&mut self) -> Result<azalea_nbt::Tag, String> { fn read_nbt(&mut self) -> Result<azalea_nbt::Tag, String> {
match azalea_nbt::Tag::read(self).await { match azalea_nbt::Tag::read(self) {
Ok(r) => Ok(r), Ok(r) => Ok(r),
// Err(e) => Err(e.to_string()), // Err(e) => Err(e.to_string()),
Err(e) => Err(e.to_string()).unwrap(), Err(e) => Err(e.to_string()).unwrap(),
} }
} }
async fn read_long(&mut self) -> Result<i64, String> { fn read_long(&mut self) -> Result<i64, String> {
match AsyncReadExt::read_i64(self).await { match self.read_i64::<BE>() {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(_) => Err("Error reading long".to_string()), Err(_) => Err("Error reading long".to_string()),
} }
} }
async fn read_resource_location(&mut self) -> Result<ResourceLocation, String> { fn read_resource_location(&mut self) -> Result<ResourceLocation, String> {
// get the resource location from the string // get the resource location from the string
let location_string = self.read_utf().await?; let location_string = self.read_utf()?;
let location = ResourceLocation::new(&location_string)?; let location = ResourceLocation::new(&location_string)?;
Ok(location) Ok(location)
} }
async fn read_short(&mut self) -> Result<i16, String> { fn read_short(&mut self) -> Result<i16, String> {
match AsyncReadExt::read_i16(self).await { match self.read_i16::<BE>() {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(_) => Err("Error reading short".to_string()), Err(_) => Err("Error reading short".to_string()),
} }
} }
async fn read_float(&mut self) -> Result<f32, String> { fn read_float(&mut self) -> Result<f32, String> {
match AsyncReadExt::read_f32(self).await { match self.read_f32::<BE>() {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(_) => Err("Error reading float".to_string()), Err(_) => Err("Error reading float".to_string()),
} }
} }
async fn read_double(&mut self) -> Result<f64, String> { fn read_double(&mut self) -> Result<f64, String> {
match AsyncReadExt::read_f64(self).await { match self.read_f64::<BE>() {
Ok(r) => Ok(r), Ok(r) => Ok(r),
Err(_) => Err("Error reading double".to_string()), Err(_) => Err("Error reading double".to_string()),
} }
} }
async fn read_uuid(&mut self) -> Result<Uuid, String> { fn read_uuid(&mut self) -> Result<Uuid, String> {
Ok(Uuid::from_int_array([ Ok(Uuid::from_int_array([
self.read_int().await? as u32, Readable::read_int(self)? as u32,
self.read_int().await? as u32, Readable::read_int(self)? as u32,
self.read_int().await? as u32, Readable::read_int(self)? as u32,
self.read_int().await? as u32, Readable::read_int(self)? as u32,
])) ]))
} }
} }
#[async_trait] // 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
pub async fn read_varint_async(reader: &mut (dyn AsyncRead + Unpin + Send)) -> Result<i32, String> {
let mut buffer = [0];
let mut ans = 0;
for i in 0..5 {
reader
.read_exact(&mut buffer)
.await
.map_err(|_| "Invalid VarInt".to_string())?;
ans |= ((buffer[0] & 0b0111_1111) as i32) << (7 * i);
if buffer[0] & 0b1000_0000 == 0 {
return Ok(ans);
}
}
Ok(ans)
}
pub trait McBufReadable pub trait McBufReadable
where where
Self: Sized, Self: Sized,
{ {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String>;
where
R: AsyncRead + std::marker::Unpin + std::marker::Send;
} }
#[async_trait]
pub trait McBufVarintReadable pub trait McBufVarintReadable
where where
Self: Sized, Self: Sized,
{ {
async fn varint_read_into<R>(buf: &mut R) -> Result<Self, String> fn varint_read_into(buf: &mut impl Read) -> Result<Self, String>;
where
R: AsyncRead + std::marker::Unpin + std::marker::Send;
} }
#[async_trait]
impl McBufReadable for i32 { impl McBufReadable for i32 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where Readable::read_int(buf)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_int().await
} }
} }
#[async_trait]
impl McBufVarintReadable for i32 { impl McBufVarintReadable for i32 {
async fn varint_read_into<R>(buf: &mut R) -> Result<Self, String> fn varint_read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_varint()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_varint().await
} }
} }
#[async_trait]
impl McBufReadable for UnsizedByteArray { impl McBufReadable for UnsizedByteArray {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where Ok(UnsizedByteArray(buf.read_bytes()?))
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
Ok(UnsizedByteArray(buf.read_bytes().await?))
} }
} }
#[async_trait]
impl<T: McBufReadable + Send> McBufReadable for Vec<T> { impl<T: McBufReadable + Send> McBufReadable for Vec<T> {
default async fn read_into<R>(buf: &mut R) -> Result<Self, String> default fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let length = buf.read_varint()? as usize;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let length = buf.read_varint().await? as usize;
let mut contents = Vec::with_capacity(length); let mut contents = Vec::with_capacity(length);
for _ in 0..length { for _ in 0..length {
contents.push(T::read_into(buf).await?); contents.push(T::read_into(buf)?);
} }
Ok(contents) Ok(contents)
} }
} }
#[async_trait]
impl McBufReadable for Vec<u8> { impl McBufReadable for Vec<u8> {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_byte_array()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_byte_array().await
} }
} }
// string // string
#[async_trait]
impl McBufReadable for String { impl McBufReadable for String {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_utf()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_utf().await
} }
} }
// ResourceLocation // ResourceLocation
#[async_trait]
impl McBufReadable for ResourceLocation { impl McBufReadable for ResourceLocation {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_resource_location()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_resource_location().await
} }
} }
// u32 // u32
#[async_trait]
impl McBufReadable for u32 { impl McBufReadable for u32 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where Readable::read_int(buf).map(|i| i as u32)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_int().await.map(|i| i as u32)
} }
} }
// u32 varint // u32 varint
#[async_trait]
impl McBufVarintReadable for u32 { impl McBufVarintReadable for u32 {
async fn varint_read_into<R>(buf: &mut R) -> Result<Self, String> fn varint_read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_varint().map(|i| i as u32)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_varint().await.map(|i| i as u32)
} }
} }
// u16 // u16
#[async_trait]
impl McBufReadable for u16 { impl McBufReadable for u16 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_short().map(|i| i as u16)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_short().await.map(|i| i as u16)
} }
} }
// i16 // i16
#[async_trait]
impl McBufReadable for i16 { impl McBufReadable for i16 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_short()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_short().await
} }
} }
// u16 varint // u16 varint
#[async_trait]
impl McBufVarintReadable for u16 { impl McBufVarintReadable for u16 {
async fn varint_read_into<R>(buf: &mut R) -> Result<Self, String> fn varint_read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_varint().map(|i| i as u16)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_varint().await.map(|i| i as u16)
} }
} }
// i64 // i64
#[async_trait]
impl McBufReadable for i64 { impl McBufReadable for i64 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_long()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_long().await
} }
} }
// u64 // u64
#[async_trait]
impl McBufReadable for u64 { impl McBufReadable for u64 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where i64::read_into(buf).map(|i| i as u64)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
i64::read_into(buf).await.map(|i| i as u64)
} }
} }
// bool // bool
#[async_trait]
impl McBufReadable for bool { impl McBufReadable for bool {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_boolean()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_boolean().await
} }
} }
// u8 // u8
#[async_trait]
impl McBufReadable for u8 { impl McBufReadable for u8 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_byte()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_byte().await
} }
} }
// i8 // i8
#[async_trait]
impl McBufReadable for i8 { impl McBufReadable for i8 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_byte().map(|i| i as i8)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_byte().await.map(|i| i as i8)
} }
} }
// f32 // f32
#[async_trait]
impl McBufReadable for f32 { impl McBufReadable for f32 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_float()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_float().await
} }
} }
// f64 // f64
#[async_trait]
impl McBufReadable for f64 { impl McBufReadable for f64 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_double()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_double().await
} }
} }
// GameType // GameType
#[async_trait]
impl McBufReadable for GameType { impl McBufReadable for GameType {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where GameType::from_id(buf.read_byte()?)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
GameType::from_id(buf.read_byte().await?)
} }
} }
// Option<GameType> // Option<GameType>
#[async_trait]
impl McBufReadable for Option<GameType> { impl McBufReadable for Option<GameType> {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where GameType::from_optional_id(buf.read_byte()? as i8)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
GameType::from_optional_id(buf.read_byte().await? as i8)
} }
} }
// Option<String> // Option<String>
#[async_trait]
impl<T: McBufReadable> McBufReadable for Option<T> { impl<T: McBufReadable> McBufReadable for Option<T> {
default async fn read_into<R>(buf: &mut R) -> Result<Self, String> default fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let present = buf.read_boolean()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let present = buf.read_boolean().await?;
Ok(if present { Ok(if present {
Some(T::read_into(buf).await?) Some(T::read_into(buf)?)
} else { } else {
None None
}) })
@ -488,35 +403,23 @@ impl<T: McBufReadable> McBufReadable for Option<T> {
} }
// azalea_nbt::Tag // azalea_nbt::Tag
#[async_trait]
impl McBufReadable for azalea_nbt::Tag { impl McBufReadable for azalea_nbt::Tag {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_nbt()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_nbt().await
} }
} }
// Difficulty // Difficulty
#[async_trait]
impl McBufReadable for Difficulty { impl McBufReadable for Difficulty {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where Ok(Difficulty::by_id(u8::read_into(buf)?))
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
Ok(Difficulty::by_id(u8::read_into(buf).await?))
} }
} }
// Component // Component
#[async_trait]
impl McBufReadable for Component { impl McBufReadable for Component {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let string = buf.read_utf()?;
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()) let json: serde_json::Value = serde_json::from_str(string.as_str())
.map_err(|e| "Component isn't valid JSON".to_string())?; .map_err(|e| "Component isn't valid JSON".to_string())?;
let component = Component::deserialize(json).map_err(|e| e.to_string())?; let component = Component::deserialize(json).map_err(|e| e.to_string())?;
@ -525,42 +428,30 @@ impl McBufReadable for Component {
} }
// Slot // Slot
#[async_trait]
impl McBufReadable for Slot { impl McBufReadable for Slot {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let present = buf.read_boolean()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let present = buf.read_boolean().await?;
if !present { if !present {
return Ok(Slot::Empty); return Ok(Slot::Empty);
} }
let id = buf.read_varint().await?; let id = buf.read_varint()?;
let count = buf.read_byte().await?; let count = buf.read_byte()?;
let nbt = buf.read_nbt().await?; let nbt = buf.read_nbt()?;
Ok(Slot::Present(SlotData { id, count, nbt })) Ok(Slot::Present(SlotData { id, count, nbt }))
} }
} }
// Uuid // Uuid
#[async_trait]
impl McBufReadable for Uuid { impl McBufReadable for Uuid {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where buf.read_uuid()
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_uuid().await
} }
} }
// BlockPos // BlockPos
#[async_trait]
impl McBufReadable for BlockPos { impl McBufReadable for BlockPos {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let val = u64::read_into(buf)?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let val = u64::read_into(buf).await?;
let x = (val >> 38) as i32; let x = (val >> 38) as i32;
let y = (val & 0xFFF) as i32; let y = (val & 0xFFF) as i32;
let z = ((val >> 12) & 0x3FFFFFF) as i32; let z = ((val >> 12) & 0x3FFFFFF) as i32;
@ -569,13 +460,9 @@ impl McBufReadable for BlockPos {
} }
// Direction // Direction
#[async_trait]
impl McBufReadable for Direction { impl McBufReadable for Direction {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where match buf.read_varint()? {
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
match buf.read_varint().await? {
0 => Ok(Self::Down), 0 => Ok(Self::Down),
1 => Ok(Self::Up), 1 => Ok(Self::Up),
2 => Ok(Self::North), 2 => Ok(Self::North),

View file

@ -1,5 +1,4 @@
use super::{UnsizedByteArray, MAX_STRING_LENGTH}; use super::{UnsizedByteArray, MAX_STRING_LENGTH};
use async_trait::async_trait;
use azalea_chat::component::Component; use azalea_chat::component::Component;
use azalea_core::{ use azalea_core::{
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation, difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
@ -9,7 +8,6 @@ use byteorder::{BigEndian, WriteBytesExt};
use std::io::Write; use std::io::Write;
use uuid::Uuid; use uuid::Uuid;
#[async_trait]
pub trait Writable { pub trait Writable {
fn write_list<F, T>(&mut self, list: &[T], writer: F) -> Result<(), std::io::Error> fn write_list<F, T>(&mut self, list: &[T], writer: F) -> Result<(), std::io::Error>
where where
@ -48,7 +46,6 @@ pub trait Writable {
fn write_uuid(&mut self, uuid: &Uuid) -> Result<(), std::io::Error>; fn write_uuid(&mut self, uuid: &Uuid) -> Result<(), std::io::Error>;
} }
#[async_trait]
impl Writable for Vec<u8> { impl Writable for Vec<u8> {
fn write_list<F, T>(&mut self, list: &[T], writer: F) -> Result<(), std::io::Error> fn write_list<F, T>(&mut self, list: &[T], writer: F) -> Result<(), std::io::Error>
where where
@ -363,9 +360,8 @@ impl McBufWritable for Difficulty {
} }
// Component // Component
#[async_trait]
impl McBufWritable for Component { impl McBufWritable for Component {
// async fn read_into<R>(buf: &mut R) -> Result<Self, String> // async fn read_into(buf: &mut impl Read) -> Result<Self, String>
// where // where
// R: AsyncRead + std::marker::Unpin + std::marker::Send, // R: AsyncRead + std::marker::Unpin + std::marker::Send,
// { // {

View file

@ -1,9 +1,7 @@
use super::GamePacket; use super::GamePacket;
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable}; use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
use async_trait::async_trait;
use azalea_core::resource_location::ResourceLocation; use azalea_core::resource_location::ResourceLocation;
use std::hash::Hash; use std::{hash::Hash, io::Read};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWriteExt};
#[derive(Hash, Clone, Debug)] #[derive(Hash, Clone, Debug)]
pub struct ClientboundDeclareCommandsPacket { pub struct ClientboundDeclareCommandsPacket {
@ -20,16 +18,14 @@ impl ClientboundDeclareCommandsPacket {
panic!("ClientboundDeclareCommandsPacket::write not implemented") panic!("ClientboundDeclareCommandsPacket::write not implemented")
} }
pub async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>( pub fn read<T: Read>(buf: &mut T) -> Result<GamePacket, String> {
buf: &mut T, let node_count = buf.read_varint()?;
) -> Result<GamePacket, String> {
let node_count = buf.read_varint().await?;
let mut nodes = Vec::with_capacity(node_count as usize); let mut nodes = Vec::with_capacity(node_count as usize);
for _ in 0..node_count { for _ in 0..node_count {
let node = BrigadierNodeStub::read_into(buf).await?; let node = BrigadierNodeStub::read_into(buf)?;
nodes.push(node); nodes.push(node);
} }
let root_index = buf.read_varint().await?; let root_index = buf.read_varint()?;
Ok(GamePacket::ClientboundDeclareCommandsPacket( Ok(GamePacket::ClientboundDeclareCommandsPacket(
ClientboundDeclareCommandsPacket { ClientboundDeclareCommandsPacket {
entries: nodes, entries: nodes,
@ -47,20 +43,16 @@ pub struct BrigadierNumber<T> {
min: Option<T>, min: Option<T>,
max: Option<T>, max: Option<T>,
} }
#[async_trait] impl<T: McBufReadable> McBufReadable for BrigadierNumber<T> {
impl<T: McBufReadable + Send> McBufReadable for BrigadierNumber<T> { fn read_into(buf: &mut impl Read) -> Result<Self, String> {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> let flags = buf.read_byte()?;
where
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let flags = buf.read_byte().await?;
let min = if flags & 0x01 != 0 { let min = if flags & 0x01 != 0 {
Some(T::read_into(buf).await?) Some(T::read_into(buf)?)
} else { } else {
None None
}; };
let max = if flags & 0x02 != 0 { let max = if flags & 0x02 != 0 {
Some(T::read_into(buf).await?) Some(T::read_into(buf)?)
} else { } else {
None None
}; };
@ -97,13 +89,9 @@ pub enum BrigadierString {
GreedyPhrase = 2, GreedyPhrase = 2,
} }
#[async_trait]
impl McBufReadable for BrigadierString { impl McBufReadable for BrigadierString {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let id = buf.read_byte()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let id = buf.read_byte().await?;
Ok(match id { Ok(match id {
0 => BrigadierString::SingleWord, 0 => BrigadierString::SingleWord,
1 => BrigadierString::QuotablePhrase, 1 => BrigadierString::QuotablePhrase,
@ -171,38 +159,24 @@ pub enum BrigadierParser {
Resource { registry_key: ResourceLocation }, Resource { registry_key: ResourceLocation },
} }
#[async_trait]
impl McBufReadable for BrigadierParser { impl McBufReadable for BrigadierParser {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let parser = buf.read_resource_location()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let parser = buf.read_resource_location().await?;
if parser == ResourceLocation::new("brigadier:bool")? { if parser == ResourceLocation::new("brigadier:bool")? {
Ok(BrigadierParser::Bool) Ok(BrigadierParser::Bool)
} else if parser == ResourceLocation::new("brigadier:double")? { } else if parser == ResourceLocation::new("brigadier:double")? {
Ok(BrigadierParser::Double( Ok(BrigadierParser::Double(BrigadierNumber::read_into(buf)?))
BrigadierNumber::read_into(buf).await?,
))
} else if parser == ResourceLocation::new("brigadier:float")? { } else if parser == ResourceLocation::new("brigadier:float")? {
Ok(BrigadierParser::Float( Ok(BrigadierParser::Float(BrigadierNumber::read_into(buf)?))
BrigadierNumber::read_into(buf).await?,
))
} else if parser == ResourceLocation::new("brigadier:integer")? { } else if parser == ResourceLocation::new("brigadier:integer")? {
Ok(BrigadierParser::Integer( Ok(BrigadierParser::Integer(BrigadierNumber::read_into(buf)?))
BrigadierNumber::read_into(buf).await?,
))
} else if parser == ResourceLocation::new("brigadier:long")? { } else if parser == ResourceLocation::new("brigadier:long")? {
Ok(BrigadierParser::Long( Ok(BrigadierParser::Long(BrigadierNumber::read_into(buf)?))
BrigadierNumber::read_into(buf).await?,
))
} else if parser == ResourceLocation::new("brigadier:string")? { } else if parser == ResourceLocation::new("brigadier:string")? {
Ok(BrigadierParser::String( Ok(BrigadierParser::String(BrigadierString::read_into(buf)?))
BrigadierString::read_into(buf).await?,
))
} else if parser == ResourceLocation::new("minecraft:entity")? { } else if parser == ResourceLocation::new("minecraft:entity")? {
let flags = buf.read_byte().await?; let flags = buf.read_byte()?;
Ok(BrigadierParser::Entity { Ok(BrigadierParser::Entity {
single: flags & 0x01 != 0, single: flags & 0x01 != 0,
players_only: flags & 0x02 != 0, players_only: flags & 0x02 != 0,
@ -250,7 +224,7 @@ impl McBufReadable for BrigadierParser {
} else if parser == ResourceLocation::new("minecraft:scoreboard_slot")? { } else if parser == ResourceLocation::new("minecraft:scoreboard_slot")? {
Ok(BrigadierParser::ScoreboardSlot) Ok(BrigadierParser::ScoreboardSlot)
} else if parser == ResourceLocation::new("minecraft:score_holder")? { } else if parser == ResourceLocation::new("minecraft:score_holder")? {
let flags = buf.read_byte().await?; let flags = buf.read_byte()?;
Ok(BrigadierParser::ScoreHolder { Ok(BrigadierParser::ScoreHolder {
allows_multiple: flags & 0x01 != 0, allows_multiple: flags & 0x01 != 0,
}) })
@ -270,7 +244,7 @@ impl McBufReadable for BrigadierParser {
Ok(BrigadierParser::EntityAnchor) Ok(BrigadierParser::EntityAnchor)
} else if parser == ResourceLocation::new("minecraft:range")? { } else if parser == ResourceLocation::new("minecraft:range")? {
Ok(BrigadierParser::Range { Ok(BrigadierParser::Range {
decimals_allowed: buf.read_boolean().await?, decimals_allowed: buf.read_boolean()?,
}) })
} else if parser == ResourceLocation::new("minecraft:int_range")? { } else if parser == ResourceLocation::new("minecraft:int_range")? {
Ok(BrigadierParser::IntRange) Ok(BrigadierParser::IntRange)
@ -292,11 +266,11 @@ impl McBufReadable for BrigadierParser {
Ok(BrigadierParser::Time) Ok(BrigadierParser::Time)
} else if parser == ResourceLocation::new("minecraft:resource_or_tag")? { } else if parser == ResourceLocation::new("minecraft:resource_or_tag")? {
Ok(BrigadierParser::ResourceOrTag { Ok(BrigadierParser::ResourceOrTag {
registry_key: buf.read_resource_location().await?, registry_key: buf.read_resource_location()?,
}) })
} else if parser == ResourceLocation::new("minecraft:resource")? { } else if parser == ResourceLocation::new("minecraft:resource")? {
Ok(BrigadierParser::Resource { Ok(BrigadierParser::Resource {
registry_key: buf.read_resource_location().await?, registry_key: buf.read_resource_location()?,
}) })
} else { } else {
panic!("Unknown Brigadier parser: {}", parser) panic!("Unknown Brigadier parser: {}", parser)
@ -305,13 +279,9 @@ impl McBufReadable for BrigadierParser {
} }
// azalea_brigadier::tree::CommandNode // azalea_brigadier::tree::CommandNode
#[async_trait]
impl McBufReadable for BrigadierNodeStub { impl McBufReadable for BrigadierNodeStub {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let flags = u8::read_into(buf)?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let flags = u8::read_into(buf).await?;
if flags > 31 { if flags > 31 {
println!( println!(
"Warning: The flags from a Brigadier node are over 31. This is probably a bug." "Warning: The flags from a Brigadier node are over 31. This is probably a bug."
@ -323,21 +293,17 @@ impl McBufReadable for BrigadierNodeStub {
let has_redirect = flags & 0x08 != 0; let has_redirect = flags & 0x08 != 0;
let has_suggestions_type = flags & 0x10 != 0; let has_suggestions_type = flags & 0x10 != 0;
let children = buf.read_int_id_list().await?; let children = buf.read_int_id_list()?;
let redirect_node = if has_redirect { let redirect_node = if has_redirect { buf.read_varint()? } else { 0 };
buf.read_varint().await?
} else {
0
};
// argument node // argument node
if node_type == 2 { if node_type == 2 {
let name = buf.read_utf().await?; let name = buf.read_utf()?;
let parser = BrigadierParser::read_into(buf).await?; let parser = BrigadierParser::read_into(buf)?;
let suggestions_type = if has_suggestions_type { let suggestions_type = if has_suggestions_type {
Some(buf.read_resource_location().await?) Some(buf.read_resource_location()?)
} else { } else {
None None
}; };
@ -345,7 +311,7 @@ impl McBufReadable for BrigadierNodeStub {
} }
// literal node // literal node
if node_type == 1 { if node_type == 1 {
let name = buf.read_utf().await?; let name = buf.read_utf()?;
return Ok(BrigadierNodeStub {}); return Ok(BrigadierNodeStub {});
} }
Ok(BrigadierNodeStub {}) Ok(BrigadierNodeStub {})

View file

@ -1,9 +1,7 @@
// i don't know the actual name of this packet, i couldn't find it in the source code use std::io::Read;
use crate::mc_buf::{McBufReadable, McBufWritable, Readable}; use crate::mc_buf::{McBufReadable, McBufWritable, Readable};
use async_trait::async_trait;
use packet_macros::GamePacket; use packet_macros::GamePacket;
use tokio::io::AsyncRead;
#[derive(Clone, Debug, GamePacket)] #[derive(Clone, Debug, GamePacket)]
pub struct ClientboundPlayerAbilitiesPacket { pub struct ClientboundPlayerAbilitiesPacket {
@ -21,13 +19,9 @@ pub struct PlayerAbilitiesFlags {
pub instant_break: bool, pub instant_break: bool,
} }
#[async_trait]
impl McBufReadable for PlayerAbilitiesFlags { impl McBufReadable for PlayerAbilitiesFlags {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let byte = buf.read_byte()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let byte = buf.read_byte().await?;
Ok(PlayerAbilitiesFlags { Ok(PlayerAbilitiesFlags {
invulnerable: byte & 1 != 0, invulnerable: byte & 1 != 0,
flying: byte & 2 != 0, flying: byte & 2 != 0,

View file

@ -1,10 +1,7 @@
// i don't know the actual name of this packet, i couldn't find it in the source code
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable}; use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
use async_trait::async_trait;
use azalea_chat::component::Component; use azalea_chat::component::Component;
use packet_macros::{GamePacket, McBufReadable, McBufWritable}; use packet_macros::{GamePacket, McBufReadable, McBufWritable};
use tokio::io::AsyncRead; use std::io::Read;
use uuid::Uuid; use uuid::Uuid;
#[derive(Clone, Debug, GamePacket)] #[derive(Clone, Debug, GamePacket)]
@ -64,19 +61,15 @@ pub struct RemovePlayer {
uuid: Uuid, uuid: Uuid,
} }
#[async_trait]
impl McBufReadable for Action { impl McBufReadable for Action {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let id = buf.read_byte()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let id = buf.read_byte().await?;
Ok(match id { Ok(match id {
0 => Action::AddPlayer(Vec::<AddPlayer>::read_into(buf).await?), 0 => Action::AddPlayer(Vec::<AddPlayer>::read_into(buf)?),
1 => Action::UpdateGameMode(Vec::<UpdateGameMode>::read_into(buf).await?), 1 => Action::UpdateGameMode(Vec::<UpdateGameMode>::read_into(buf)?),
2 => Action::UpdateLatency(Vec::<UpdateLatency>::read_into(buf).await?), 2 => Action::UpdateLatency(Vec::<UpdateLatency>::read_into(buf)?),
3 => Action::UpdateDisplayName(Vec::<UpdateDisplayName>::read_into(buf).await?), 3 => Action::UpdateDisplayName(Vec::<UpdateDisplayName>::read_into(buf)?),
4 => Action::RemovePlayer(Vec::<RemovePlayer>::read_into(buf).await?), 4 => Action::RemovePlayer(Vec::<RemovePlayer>::read_into(buf)?),
_ => panic!("Unknown player info action id: {}", id), _ => panic!("Unknown player info action id: {}", id),
}) })
} }

View file

@ -1,9 +1,7 @@
// i don't know the actual name of this packet, i couldn't find it in the source code use std::io::Read;
use crate::mc_buf::{McBufReadable, McBufWritable, Readable}; use crate::mc_buf::{McBufReadable, McBufWritable, Readable};
use async_trait::async_trait;
use packet_macros::GamePacket; use packet_macros::GamePacket;
use tokio::io::AsyncRead;
#[derive(Clone, Debug, GamePacket)] #[derive(Clone, Debug, GamePacket)]
pub struct ClientboundPlayerPositionPacket { pub struct ClientboundPlayerPositionPacket {
@ -29,13 +27,9 @@ pub struct RelativeArguments {
pub x_rot: bool, pub x_rot: bool,
} }
#[async_trait]
impl McBufReadable for RelativeArguments { impl McBufReadable for RelativeArguments {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let byte = buf.read_byte()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let byte = buf.read_byte().await?;
Ok(RelativeArguments { Ok(RelativeArguments {
x: byte & 0b1 != 0, x: byte & 0b1 != 0,
y: byte & 0b10 != 0, y: byte & 0b10 != 0,

View file

@ -1,8 +1,6 @@
use async_trait::async_trait;
use azalea_chat::component::Component;
use azalea_core::{resource_location::ResourceLocation, Slot}; use azalea_core::{resource_location::ResourceLocation, Slot};
use packet_macros::{GamePacket, McBufReadable, McBufWritable}; use packet_macros::{GamePacket, McBufReadable, McBufWritable};
use tokio::io::AsyncRead; use std::io::Read;
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable}; use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
@ -42,13 +40,9 @@ impl McBufWritable for State {
Ok(()) Ok(())
} }
} }
#[async_trait]
impl McBufReadable for State { impl McBufReadable for State {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let state = buf.read_varint()?.try_into().unwrap();
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let state = buf.read_varint().await?.try_into().unwrap();
Ok(match state { Ok(match state {
0 => State::Init, 0 => State::Init,
1 => State::Add, 1 => State::Add,

View file

@ -1,12 +1,12 @@
use std::io::Read;
use crate::{ use crate::{
mc_buf::{Readable, Writable}, mc_buf::{Readable, Writable},
packets::{McBufReadable, McBufWritable}, packets::{McBufReadable, McBufWritable},
}; };
use async_trait::async_trait;
use azalea_chat::component::Component; use azalea_chat::component::Component;
use azalea_core::{BlockPos, Direction, Slot}; use azalea_core::{BlockPos, Direction, Slot};
use packet_macros::{GamePacket, McBufReadable, McBufWritable}; use packet_macros::{GamePacket, McBufReadable, McBufWritable};
use tokio::io::AsyncRead;
use uuid::Uuid; use uuid::Uuid;
#[derive(Clone, Debug, GamePacket)] #[derive(Clone, Debug, GamePacket)]
@ -24,19 +24,15 @@ pub struct EntityDataItem {
pub value: EntityDataValue, pub value: EntityDataValue,
} }
#[async_trait]
impl McBufReadable for Vec<EntityDataItem> { impl McBufReadable for Vec<EntityDataItem> {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let mut metadata = Vec::new(); let mut metadata = Vec::new();
loop { loop {
let index = buf.read_byte().await?; let index = buf.read_byte()?;
if index == 0xff { if index == 0xff {
break; break;
} }
let value = EntityDataValue::read_into(buf).await?; let value = EntityDataValue::read_into(buf)?;
metadata.push(EntityDataItem { index, value }); metadata.push(EntityDataItem { index, value });
} }
Ok(metadata) Ok(metadata)
@ -81,51 +77,47 @@ pub enum EntityDataValue {
Pose(Pose), Pose(Pose),
} }
#[async_trait]
impl McBufReadable for EntityDataValue { impl McBufReadable for EntityDataValue {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let type_ = buf.read_varint()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let type_ = buf.read_varint().await?;
Ok(match type_ { Ok(match type_ {
0 => EntityDataValue::Byte(buf.read_byte().await?), 0 => EntityDataValue::Byte(buf.read_byte()?),
1 => EntityDataValue::Int(buf.read_varint().await?), 1 => EntityDataValue::Int(buf.read_varint()?),
2 => EntityDataValue::Float(buf.read_float().await?), 2 => EntityDataValue::Float(buf.read_float()?),
3 => EntityDataValue::String(buf.read_utf().await?), 3 => EntityDataValue::String(buf.read_utf()?),
4 => EntityDataValue::Component(Component::read_into(buf).await?), 4 => EntityDataValue::Component(Component::read_into(buf)?),
5 => EntityDataValue::OptionalComponent(Option::<Component>::read_into(buf).await?), 5 => EntityDataValue::OptionalComponent(Option::<Component>::read_into(buf)?),
6 => EntityDataValue::ItemStack(Slot::read_into(buf).await?), 6 => EntityDataValue::ItemStack(Slot::read_into(buf)?),
7 => EntityDataValue::Boolean(buf.read_boolean().await?), 7 => EntityDataValue::Boolean(buf.read_boolean()?),
8 => EntityDataValue::Rotations { 8 => EntityDataValue::Rotations {
x: buf.read_float().await?, x: buf.read_float()?,
y: buf.read_float().await?, y: buf.read_float()?,
z: buf.read_float().await?, z: buf.read_float()?,
}, },
9 => EntityDataValue::BlockPos(BlockPos::read_into(buf).await?), 9 => EntityDataValue::BlockPos(BlockPos::read_into(buf)?),
10 => EntityDataValue::OptionalBlockPos(Option::<BlockPos>::read_into(buf).await?), 10 => EntityDataValue::OptionalBlockPos(Option::<BlockPos>::read_into(buf)?),
11 => EntityDataValue::Direction(Direction::read_into(buf).await?), 11 => EntityDataValue::Direction(Direction::read_into(buf)?),
12 => EntityDataValue::OptionalUuid(Option::<Uuid>::read_into(buf).await?), 12 => EntityDataValue::OptionalUuid(Option::<Uuid>::read_into(buf)?),
13 => EntityDataValue::OptionalBlockState({ 13 => EntityDataValue::OptionalBlockState({
let val = i32::read_into(buf).await?; let val = i32::read_into(buf)?;
if val == 0 { if val == 0 {
None None
} else { } else {
Some(val) Some(val)
} }
}), }),
14 => EntityDataValue::CompoundTag(azalea_nbt::Tag::read_into(buf).await?), 14 => EntityDataValue::CompoundTag(azalea_nbt::Tag::read_into(buf)?),
15 => EntityDataValue::Particle(Particle::read_into(buf).await?), 15 => EntityDataValue::Particle(Particle::read_into(buf)?),
16 => EntityDataValue::VillagerData(VillagerData::read_into(buf).await?), 16 => EntityDataValue::VillagerData(VillagerData::read_into(buf)?),
17 => EntityDataValue::OptionalUnsignedInt({ 17 => EntityDataValue::OptionalUnsignedInt({
let val = buf.read_varint().await?; let val = buf.read_varint()?;
if val == 0 { if val == 0 {
None None
} else { } else {
Some((val - 1) as u32) Some((val - 1) as u32)
} }
}), }),
18 => EntityDataValue::Pose(Pose::read_into(buf).await?), 18 => EntityDataValue::Pose(Pose::read_into(buf)?),
_ => return Err(format!("Unknown entity data type: {}", type_)), _ => return Err(format!("Unknown entity data type: {}", type_)),
}) })
} }
@ -309,18 +301,14 @@ pub struct VibrationParticle {
pub ticks: u32, pub ticks: u32,
} }
#[async_trait]
impl McBufReadable for ParticleData { impl McBufReadable for ParticleData {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let id = buf.read_varint()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let id = buf.read_varint().await?;
Ok(match id { Ok(match id {
0 => ParticleData::AmbientEntityEffect, 0 => ParticleData::AmbientEntityEffect,
1 => ParticleData::AngryVillager, 1 => ParticleData::AngryVillager,
2 => ParticleData::Block(BlockParticle::read_into(buf).await?), 2 => ParticleData::Block(BlockParticle::read_into(buf)?),
3 => ParticleData::BlockMarker(BlockParticle::read_into(buf).await?), 3 => ParticleData::BlockMarker(BlockParticle::read_into(buf)?),
4 => ParticleData::Bubble, 4 => ParticleData::Bubble,
5 => ParticleData::Cloud, 5 => ParticleData::Cloud,
6 => ParticleData::Crit, 6 => ParticleData::Crit,
@ -331,10 +319,8 @@ impl McBufReadable for ParticleData {
11 => ParticleData::LandingLava, 11 => ParticleData::LandingLava,
12 => ParticleData::DrippingWater, 12 => ParticleData::DrippingWater,
13 => ParticleData::FallingWater, 13 => ParticleData::FallingWater,
14 => ParticleData::Dust(DustParticle::read_into(buf).await?), 14 => ParticleData::Dust(DustParticle::read_into(buf)?),
15 => ParticleData::DustColorTransition( 15 => ParticleData::DustColorTransition(DustColorTransitionParticle::read_into(buf)?),
DustColorTransitionParticle::read_into(buf).await?,
),
16 => ParticleData::Effect, 16 => ParticleData::Effect,
17 => ParticleData::ElderGuardian, 17 => ParticleData::ElderGuardian,
18 => ParticleData::EnchantedHit, 18 => ParticleData::EnchantedHit,
@ -343,7 +329,7 @@ impl McBufReadable for ParticleData {
21 => ParticleData::EntityEffect, 21 => ParticleData::EntityEffect,
22 => ParticleData::ExplosionEmitter, 22 => ParticleData::ExplosionEmitter,
23 => ParticleData::Explosion, 23 => ParticleData::Explosion,
24 => ParticleData::FallingDust(BlockParticle::read_into(buf).await?), 24 => ParticleData::FallingDust(BlockParticle::read_into(buf)?),
25 => ParticleData::Firework, 25 => ParticleData::Firework,
26 => ParticleData::Fishing, 26 => ParticleData::Fishing,
27 => ParticleData::Flame, 27 => ParticleData::Flame,
@ -354,8 +340,8 @@ impl McBufReadable for ParticleData {
32 => ParticleData::Composter, 32 => ParticleData::Composter,
33 => ParticleData::Heart, 33 => ParticleData::Heart,
34 => ParticleData::InstantEffect, 34 => ParticleData::InstantEffect,
35 => ParticleData::Item(ItemParticle::read_into(buf).await?), 35 => ParticleData::Item(ItemParticle::read_into(buf)?),
36 => ParticleData::Vibration(VibrationParticle::read_into(buf).await?), 36 => ParticleData::Vibration(VibrationParticle::read_into(buf)?),
37 => ParticleData::ItemSlime, 37 => ParticleData::ItemSlime,
38 => ParticleData::ItemSnowball, 38 => ParticleData::ItemSnowball,
39 => ParticleData::LargeSmoke, 39 => ParticleData::LargeSmoke,

View file

@ -1,10 +1,8 @@
use async_trait::async_trait;
use azalea_core::{game_type::GameType, resource_location::ResourceLocation};
use packet_macros::{GamePacket, McBufReadable, McBufWritable};
use tokio::io::AsyncRead;
use uuid::Uuid;
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable}; use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
use azalea_core::resource_location::ResourceLocation;
use packet_macros::{GamePacket, McBufReadable, McBufWritable};
use std::io::Read;
use uuid::Uuid;
#[derive(Clone, Debug, GamePacket)] #[derive(Clone, Debug, GamePacket)]
pub struct ClientboundUpdateAttributesPacket { pub struct ClientboundUpdateAttributesPacket {
@ -34,13 +32,9 @@ enum Operation {
MultiplyTotal = 2, MultiplyTotal = 2,
} }
#[async_trait]
impl McBufReadable for Operation { impl McBufReadable for Operation {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where match buf.read_byte()? {
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
match buf.read_byte().await? {
0 => Ok(Operation::Addition), 0 => Ok(Operation::Addition),
1 => Ok(Operation::MultiplyBase), 1 => Ok(Operation::MultiplyBase),
2 => Ok(Operation::MultiplyTotal), 2 => Ok(Operation::MultiplyTotal),

View file

@ -1,8 +1,7 @@
use async_trait::async_trait; use std::io::Read;
use azalea_chat::component::Component;
use azalea_core::{resource_location::ResourceLocation, Slot}; use azalea_core::{resource_location::ResourceLocation, Slot};
use packet_macros::{GamePacket, McBufReadable, McBufWritable}; use packet_macros::{GamePacket, McBufReadable, McBufWritable};
use tokio::io::AsyncRead;
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable}; use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
@ -48,20 +47,16 @@ impl McBufWritable for ShapedRecipe {
Ok(()) Ok(())
} }
} }
#[async_trait]
impl McBufReadable for ShapedRecipe { impl McBufReadable for ShapedRecipe {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let width = buf.read_varint()?.try_into().unwrap();
R: AsyncRead + std::marker::Unpin + std::marker::Send, let height = buf.read_varint()?.try_into().unwrap();
{ let group = buf.read_utf()?;
let width = buf.read_varint().await?.try_into().unwrap();
let height = buf.read_varint().await?.try_into().unwrap();
let group = buf.read_utf().await?;
let mut ingredients = Vec::with_capacity(width * height); let mut ingredients = Vec::with_capacity(width * height);
for _ in 0..width * height { for _ in 0..width * height {
ingredients.push(Ingredient::read_into(buf).await?); ingredients.push(Ingredient::read_into(buf)?);
} }
let result = Slot::read_into(buf).await?; let result = Slot::read_into(buf)?;
Ok(ShapedRecipe { Ok(ShapedRecipe {
width, width,
@ -132,22 +127,18 @@ impl McBufWritable for Recipe {
} }
} }
#[async_trait]
impl McBufReadable for Recipe { impl McBufReadable for Recipe {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let recipe_type = buf.read_resource_location()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send, let identifier = buf.read_resource_location()?;
{
let recipe_type = buf.read_resource_location().await?;
let identifier = buf.read_resource_location().await?;
// rust doesn't let us match ResourceLocation so we have to do a big // rust doesn't let us match ResourceLocation so we have to do a big
// if-else chain :( // if-else chain :(
let data = if recipe_type == ResourceLocation::new("minecraft:crafting_shapeless").unwrap() let data = if recipe_type == ResourceLocation::new("minecraft:crafting_shapeless").unwrap()
{ {
RecipeData::CraftingShapeless(ShapelessRecipe::read_into(buf).await?) RecipeData::CraftingShapeless(ShapelessRecipe::read_into(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:crafting_shaped").unwrap() { } else if recipe_type == ResourceLocation::new("minecraft:crafting_shaped").unwrap() {
RecipeData::CraftingShaped(ShapedRecipe::read_into(buf).await?) RecipeData::CraftingShaped(ShapedRecipe::read_into(buf)?)
} else if recipe_type } else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_armordye").unwrap() == ResourceLocation::new("minecraft:crafting_special_armordye").unwrap()
{ {
@ -205,17 +196,17 @@ impl McBufReadable for Recipe {
{ {
RecipeData::CraftingSpecialSuspiciousStew RecipeData::CraftingSpecialSuspiciousStew
} else if recipe_type == ResourceLocation::new("minecraft:smelting").unwrap() { } else if recipe_type == ResourceLocation::new("minecraft:smelting").unwrap() {
RecipeData::Smelting(CookingRecipe::read_into(buf).await?) RecipeData::Smelting(CookingRecipe::read_into(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:blasting").unwrap() { } else if recipe_type == ResourceLocation::new("minecraft:blasting").unwrap() {
RecipeData::Blasting(CookingRecipe::read_into(buf).await?) RecipeData::Blasting(CookingRecipe::read_into(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:smoking").unwrap() { } else if recipe_type == ResourceLocation::new("minecraft:smoking").unwrap() {
RecipeData::Smoking(CookingRecipe::read_into(buf).await?) RecipeData::Smoking(CookingRecipe::read_into(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:campfire_cooking").unwrap() { } else if recipe_type == ResourceLocation::new("minecraft:campfire_cooking").unwrap() {
RecipeData::CampfireCooking(CookingRecipe::read_into(buf).await?) RecipeData::CampfireCooking(CookingRecipe::read_into(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:stonecutting").unwrap() { } else if recipe_type == ResourceLocation::new("minecraft:stonecutting").unwrap() {
RecipeData::Stonecutting(StoneCuttingRecipe::read_into(buf).await?) RecipeData::Stonecutting(StoneCuttingRecipe::read_into(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:smithing").unwrap() { } else if recipe_type == ResourceLocation::new("minecraft:smithing").unwrap() {
RecipeData::Smithing(SmithingRecipe::read_into(buf).await?) RecipeData::Smithing(SmithingRecipe::read_into(buf)?)
} else { } else {
panic!("Unknown recipe type sent by server: {}", recipe_type); panic!("Unknown recipe type sent by server: {}", recipe_type);
}; };

View file

@ -1,11 +1,7 @@
use std::collections::HashMap; use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
use async_trait::async_trait;
use azalea_core::resource_location::ResourceLocation; use azalea_core::resource_location::ResourceLocation;
use packet_macros::GamePacket; use packet_macros::GamePacket;
use tokio::io::AsyncRead; use std::{collections::HashMap, io::Read};
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
#[derive(Clone, Debug, GamePacket)] #[derive(Clone, Debug, GamePacket)]
pub struct ClientboundUpdateTagsPacket { pub struct ClientboundUpdateTagsPacket {
@ -18,20 +14,16 @@ pub struct Tags {
pub elements: Vec<i32>, pub elements: Vec<i32>,
} }
#[async_trait]
impl McBufReadable for HashMap<ResourceLocation, Vec<Tags>> { impl McBufReadable for HashMap<ResourceLocation, Vec<Tags>> {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let length = buf.read_varint()? as usize;
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
let length = buf.read_varint().await? as usize;
let mut data = HashMap::with_capacity(length); let mut data = HashMap::with_capacity(length);
for _ in 0..length { for _ in 0..length {
let tag_type = buf.read_resource_location().await?; let tag_type = buf.read_resource_location()?;
let tags_count = buf.read_varint().await? as usize; let tags_count = buf.read_varint()? as usize;
let mut tags_vec = Vec::with_capacity(tags_count); let mut tags_vec = Vec::with_capacity(tags_count);
for _ in 0..tags_count { for _ in 0..tags_count {
let tags = Tags::read_into(buf).await?; let tags = Tags::read_into(buf)?;
tags_vec.push(tags); tags_vec.push(tags);
} }
data.insert(tag_type, tags_vec); data.insert(tag_type, tags_vec);
@ -50,14 +42,10 @@ impl McBufWritable for HashMap<ResourceLocation, Vec<Tags>> {
Ok(()) Ok(())
} }
} }
#[async_trait]
impl McBufReadable for Tags { impl McBufReadable for Tags {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where let name = buf.read_resource_location()?;
R: AsyncRead + std::marker::Unpin + std::marker::Send, let elements = buf.read_int_id_list()?;
{
let name = buf.read_resource_location().await?;
let elements = buf.read_int_id_list().await?;
Ok(Tags { name, elements }) Ok(Tags { name, elements })
} }
} }

View file

@ -1,5 +1,3 @@
// i don't know the actual name of this packet, i couldn't find it in the source code
use packet_macros::GamePacket; use packet_macros::GamePacket;
#[derive(Clone, Debug, GamePacket)] #[derive(Clone, Debug, GamePacket)]

View file

@ -1,5 +1,3 @@
// 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 crate::mc_buf::UnsizedByteArray;
use azalea_core::resource_location::ResourceLocation; use azalea_core::resource_location::ResourceLocation;
use packet_macros::GamePacket; use packet_macros::GamePacket;

View file

@ -1,9 +1,7 @@
use crate::{mc_buf::Writable, packets::ConnectionProtocol}; use crate::packets::ConnectionProtocol;
use packet_macros::HandshakePacket; use packet_macros::HandshakePacket;
use std::hash::Hash; use std::hash::Hash;
use super::HandshakePacket;
#[derive(Hash, Clone, Debug, HandshakePacket)] #[derive(Hash, Clone, Debug, HandshakePacket)]
pub struct ClientIntentionPacket { pub struct ClientIntentionPacket {
#[varint] #[varint]
@ -12,23 +10,3 @@ pub struct ClientIntentionPacket {
pub port: u16, pub port: u16,
pub intention: ConnectionProtocol, pub intention: ConnectionProtocol,
} }
// impl ClientIntentionPacket {
// pub fn get(self) -> HandshakePacket {
// HandshakePacket::ClientIntentionPacket(self)
// }
// pub fn write(&self, buf: &mut Vec<u8>) -> 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<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>(
// buf: &mut T,
// ) -> Result<HandshakePacket, String> {
// todo!()
// }
// }

View file

@ -1,3 +1,5 @@
use std::io::Read;
use super::LoginPacket; use super::LoginPacket;
use crate::mc_buf::{Readable, Writable}; use crate::mc_buf::{Readable, Writable};
use azalea_auth::game_profile::GameProfile; use azalea_auth::game_profile::GameProfile;
@ -23,17 +25,15 @@ impl ClientboundGameProfilePacket {
Ok(()) Ok(())
} }
pub async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>( pub fn read(buf: &mut impl Read) -> Result<LoginPacket, String> {
buf: &mut T,
) -> Result<LoginPacket, String> {
// TODO: we have a thing to read from the uuid now // TODO: we have a thing to read from the uuid now
let uuid = Uuid::from_int_array([ let uuid = Uuid::from_int_array([
buf.read_int().await? as u32, buf.read_int()? as u32,
buf.read_int().await? as u32, buf.read_int()? as u32,
buf.read_int().await? as u32, buf.read_int()? as u32,
buf.read_int().await? as u32, buf.read_int()? as u32,
]); ]);
let name = buf.read_utf_with_len(16).await?; let name = buf.read_utf_with_len(16)?;
Ok(ClientboundGameProfilePacket { Ok(ClientboundGameProfilePacket {
game_profile: GameProfile::new(uuid, name), game_profile: GameProfile::new(uuid, name),
} }

View file

@ -1,4 +1,4 @@
use std::hash::Hash; use std::{hash::Hash, io::Read};
use super::LoginPacket; use super::LoginPacket;
use crate::mc_buf::Readable; use crate::mc_buf::Readable;
@ -19,12 +19,10 @@ impl ClientboundHelloPacket {
panic!("ClientboundHelloPacket::write not implemented") panic!("ClientboundHelloPacket::write not implemented")
} }
pub async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>( pub fn read(buf: &mut impl Read) -> Result<LoginPacket, String> {
buf: &mut T, let server_id = buf.read_utf_with_len(20)?;
) -> Result<LoginPacket, String> { let public_key = buf.read_byte_array()?;
let server_id = buf.read_utf_with_len(20).await?; let nonce = buf.read_byte_array()?;
let public_key = buf.read_byte_array().await?;
let nonce = buf.read_byte_array().await?;
Ok(ClientboundHelloPacket { Ok(ClientboundHelloPacket {
server_id, server_id,

View file

@ -1,4 +1,4 @@
use std::hash::Hash; use std::{hash::Hash, io::Read};
use crate::mc_buf::{Readable, Writable}; use crate::mc_buf::{Readable, Writable};
@ -19,10 +19,8 @@ impl ClientboundLoginCompressionPacket {
Ok(()) Ok(())
} }
pub async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>( pub fn read(buf: &mut impl Read) -> Result<LoginPacket, String> {
buf: &mut T, let compression_threshold = buf.read_varint()?;
) -> Result<LoginPacket, String> {
let compression_threshold = buf.read_varint().await?;
Ok(ClientboundLoginCompressionPacket { Ok(ClientboundLoginCompressionPacket {
compression_threshold, compression_threshold,

View file

@ -3,14 +3,14 @@ pub mod handshake;
pub mod login; pub mod login;
pub mod status; pub mod status;
use std::io::Read;
use crate::{ use crate::{
connect::PacketFlow, connect::PacketFlow,
mc_buf::{McBufReadable, McBufWritable, Readable, Writable}, mc_buf::{McBufReadable, McBufWritable, Readable, Writable},
}; };
use async_trait::async_trait;
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use tokio::io::AsyncRead;
pub const PROTOCOL_VERSION: u32 = 758; pub const PROTOCOL_VERSION: u32 = 758;
@ -31,7 +31,6 @@ pub enum Packet {
} }
/// An enum of packets for a certain protocol /// An enum of packets for a certain protocol
#[async_trait]
pub trait ProtocolPacket pub trait ProtocolPacket
where where
Self: Sized, Self: Sized,
@ -39,24 +38,14 @@ where
fn id(&self) -> u32; fn id(&self) -> u32;
/// Read a packet by its id, ConnectionProtocol, and flow /// Read a packet by its id, ConnectionProtocol, and flow
async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>( fn read(id: u32, flow: &PacketFlow, buf: &mut impl Read) -> Result<Self, String>;
id: u32,
flow: &PacketFlow,
buf: &mut T,
) -> Result<Self, String>
where
Self: Sized;
fn write(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error>; fn write(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error>;
} }
#[async_trait]
impl McBufReadable for ConnectionProtocol { impl McBufReadable for ConnectionProtocol {
async fn read_into<R>(buf: &mut R) -> Result<Self, String> fn read_into(buf: &mut impl Read) -> Result<Self, String> {
where ConnectionProtocol::from_i32(buf.read_varint()?)
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
ConnectionProtocol::from_i32(buf.read_varint().await?)
.ok_or_else(|| "Invalid intention".to_string()) .ok_or_else(|| "Invalid intention".to_string())
} }
} }

View file

@ -1,3 +1,5 @@
use std::io::Read;
use azalea_chat::component::Component; use azalea_chat::component::Component;
use serde::Deserialize; use serde::Deserialize;
use serde_json::Value; use serde_json::Value;
@ -43,10 +45,8 @@ impl ClientboundStatusResponsePacket {
Ok(()) Ok(())
} }
pub async fn read<T: tokio::io::AsyncRead + std::marker::Unpin + std::marker::Send>( pub fn read(buf: &mut impl Read) -> Result<StatusPacket, String> {
buf: &mut T, let status_string = buf.read_utf()?;
) -> Result<StatusPacket, String> {
let status_string = buf.read_utf().await?;
let status_json: Value = let status_json: Value =
serde_json::from_str(status_string.as_str()).expect("Server status isn't valid JSON"); serde_json::from_str(status_string.as_str()).expect("Server status isn't valid JSON");

View file

@ -1,12 +1,16 @@
use crate::{
connect::PacketFlow,
mc_buf::{read_varint_async, Readable},
packets::ProtocolPacket,
};
use azalea_crypto::Aes128CfbDec;
use flate2::read::ZlibDecoder;
use std::{ use std::{
cell::Cell, cell::Cell,
io::Read,
pin::Pin, pin::Pin,
task::{Context, Poll}, task::{Context, Poll},
}; };
use crate::{connect::PacketFlow, mc_buf::Readable, packets::ProtocolPacket};
use async_compression::tokio::bufread::ZlibDecoder;
use azalea_crypto::Aes128CfbDec;
use tokio::io::{AsyncRead, AsyncReadExt}; use tokio::io::{AsyncRead, AsyncReadExt};
async fn frame_splitter<R: ?Sized>(mut stream: &mut R) -> Result<Vec<u8>, String> async fn frame_splitter<R: ?Sized>(mut stream: &mut R) -> Result<Vec<u8>, String>
@ -14,7 +18,7 @@ where
R: AsyncRead + std::marker::Unpin + std::marker::Send, R: AsyncRead + std::marker::Unpin + std::marker::Send,
{ {
// Packet Length // Packet Length
let length_result = stream.read_varint().await; let length_result = read_varint_async(&mut stream).await;
match length_result { match length_result {
Ok(length) => { Ok(length) => {
let mut buf = vec![0; length as usize]; let mut buf = vec![0; length as usize];
@ -30,16 +34,13 @@ where
} }
} }
async fn packet_decoder<P: ProtocolPacket, R>( fn packet_decoder<P: ProtocolPacket>(
stream: &mut R, stream: &mut impl Read,
flow: &PacketFlow, flow: &PacketFlow,
) -> Result<P, String> ) -> Result<P, String> {
where
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
// Packet ID // Packet ID
let packet_id = stream.read_varint().await?; let packet_id = stream.read_varint()?;
P::read(packet_id.try_into().unwrap(), flow, stream).await P::read(packet_id.try_into().unwrap(), flow, stream)
} }
// this is always true in multiplayer, false in singleplayer // this is always true in multiplayer, false in singleplayer
@ -47,22 +48,16 @@ static VALIDATE_DECOMPRESSED: bool = true;
pub static MAXIMUM_UNCOMPRESSED_LENGTH: u32 = 2097152; pub static MAXIMUM_UNCOMPRESSED_LENGTH: u32 = 2097152;
async fn compression_decoder<R>( fn compression_decoder(
stream: &mut R, stream: &mut impl Read,
compression_threshold: u32, compression_threshold: u32,
) -> Result<Vec<u8>, String> ) -> Result<Vec<u8>, String> {
where
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
// Data Length // Data Length
let n: u32 = stream.read_varint().await?.try_into().unwrap(); let n: u32 = stream.read_varint()?.try_into().unwrap();
if n == 0 { if n == 0 {
// no data size, no compression // no data size, no compression
let mut buf = vec![]; let mut buf = vec![];
stream stream.read_to_end(&mut buf).map_err(|e| e.to_string())?;
.read_to_end(&mut buf)
.await
.map_err(|e| e.to_string())?;
return Ok(buf); return Ok(buf);
} }
@ -81,17 +76,10 @@ where
} }
} }
let mut buf = vec![];
stream
.read_to_end(&mut buf)
.await
.map_err(|e| e.to_string())?;
let mut decoded_buf = vec![]; let mut decoded_buf = vec![];
let mut decoder = ZlibDecoder::new(buf.as_slice()); let mut decoder = ZlibDecoder::new(stream);
decoder decoder
.read_to_end(&mut decoded_buf) .read_to_end(&mut decoded_buf)
.await
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
Ok(decoded_buf) Ok(decoded_buf)
@ -161,11 +149,11 @@ where
// "decompressing packet ({}ms)", // "decompressing packet ({}ms)",
// start_time.elapsed().as_millis() // start_time.elapsed().as_millis()
// ); // );
buf = compression_decoder(&mut buf.as_slice(), compression_threshold).await?; buf = compression_decoder(&mut &buf[..], compression_threshold)?;
} }
// println!("decoding packet ({}ms)", start_time.elapsed().as_millis()); // println!("decoding packet ({}ms)", start_time.elapsed().as_millis());
let packet = packet_decoder(&mut buf.as_slice(), flow).await?; let packet = packet_decoder(&mut buf.as_slice(), flow)?;
// println!("decoded packet ({}ms)", start_time.elapsed().as_millis()); // println!("decoded packet ({}ms)", start_time.elapsed().as_millis());
Ok(packet) Ok(packet)