mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
Merge branch 'main' into chunk-decoding
This commit is contained in:
commit
bec2da64d8
29 changed files with 471 additions and 799 deletions
36
Cargo.lock
generated
36
Cargo.lock
generated
|
@ -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",
|
||||||
|
@ -306,7 +303,6 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"criterion-plot",
|
"criterion-plot",
|
||||||
"csv",
|
"csv",
|
||||||
"futures",
|
|
||||||
"itertools",
|
"itertools",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
@ -319,7 +315,6 @@ dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tinytemplate",
|
"tinytemplate",
|
||||||
"tokio",
|
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -445,9 +440,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",
|
||||||
|
@ -465,20 +460,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"
|
||||||
|
@ -486,7 +467,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]]
|
||||||
|
@ -520,7 +500,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",
|
||||||
|
@ -729,12 +708,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]]
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -19,23 +19,19 @@ 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);
|
||||||
|
|
||||||
group.throughput(Throughput::Bytes(decoded_src.len() as u64));
|
group.throughput(Throughput::Bytes(decoded_src.len() as u64));
|
||||||
|
|
||||||
// group.bench_function("Decode", |b| {
|
group.bench_function("Decode", |b| {
|
||||||
// b.to_async(tokio::runtime::Runtime::new().unwrap())
|
b.iter(|| {
|
||||||
// .iter(|| async {
|
let mut owned_decoded_src_stream = decoded_src_stream.clone();
|
||||||
// let mut owned_decoded_src_stream = decoded_src_stream.clone();
|
owned_decoded_src_stream.seek(SeekFrom::Start(0)).unwrap();
|
||||||
// owned_decoded_src_stream.seek(SeekFrom::Start(0)).unwrap();
|
Tag::read(&mut owned_decoded_src_stream).unwrap();
|
||||||
// Tag::read(&mut owned_decoded_src_stream).await.unwrap();
|
})
|
||||||
// })
|
});
|
||||||
// });
|
|
||||||
|
|
||||||
group.bench_function("Encode", |b| {
|
group.bench_function("Encode", |b| {
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
|
|
|
@ -1,64 +1,57 @@
|
||||||
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(stream: &mut impl Read) -> Result<String, Error> {
|
||||||
where
|
let length = stream.read_u16::<BE>()?;
|
||||||
R: AsyncRead + std::marker::Unpin,
|
|
||||||
{
|
|
||||||
let length = stream.read_u16().await?;
|
|
||||||
|
|
||||||
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(stream: &mut impl Read, id: u8) -> Result<Tag, Error> {
|
||||||
async fn read_known<R>(stream: &mut R, id: u8) -> Result<Tag, Error>
|
|
||||||
where
|
|
||||||
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
|
||||||
{
|
|
||||||
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 +61,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 +74,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 +88,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 +110,29 @@ impl Tag {
|
||||||
Ok(tag)
|
Ok(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read<R>(stream: &mut R) -> Result<Tag, Error>
|
pub fn read(stream: &mut impl Read) -> Result<Tag, Error> {
|
||||||
where
|
|
||||||
R: AsyncRead + std::marker::Unpin + std::marker::Send,
|
|
||||||
{
|
|
||||||
// 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(stream: &mut impl BufRead) -> Result<Tag, Error> {
|
||||||
where
|
|
||||||
R: AsyncBufRead + std::marker::Unpin + std::marker::Send,
|
|
||||||
{
|
|
||||||
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(stream: &mut impl Read) -> Result<Tag, Error> {
|
||||||
where
|
let mut gz = GzDecoder::new(stream);
|
||||||
R: AsyncBufRead + std::marker::Unpin + std::marker::Send,
|
Tag::read(&mut gz)
|
||||||
{
|
|
||||||
let mut gz = GzipDecoder::new(stream);
|
|
||||||
Tag::read(&mut gz).await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
// {
|
// {
|
||||||
|
|
|
@ -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 {})
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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!()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
|
|
|
@ -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.as_slice(), 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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue