aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xCargo.lock23
-rw-r--r--Cargo.toml1
-rw-r--r--azalea-buf/Cargo.toml11
-rw-r--r--azalea-buf/README.md3
-rw-r--r--azalea-buf/buf-macros/Cargo.toml13
-rw-r--r--azalea-buf/buf-macros/src/lib.rs177
-rw-r--r--azalea-buf/src/definitions.rs39
-rw-r--r--azalea-buf/src/lib.rs (renamed from azalea-protocol/src/mc_buf/mod.rs)51
-rw-r--r--azalea-buf/src/read.rs (renamed from azalea-protocol/src/mc_buf/read.rs)149
-rw-r--r--azalea-buf/src/write.rs (renamed from azalea-protocol/src/mc_buf/write.rs)152
-rwxr-xr-xazalea-chat/Cargo.toml1
-rwxr-xr-xazalea-chat/src/component.rs27
-rw-r--r--azalea-client/src/client.rs51
-rwxr-xr-xazalea-core/Cargo.toml1
-rw-r--r--azalea-core/src/delta.rs26
-rwxr-xr-xazalea-core/src/difficulty.rs12
-rw-r--r--azalea-core/src/direction.rs2
-rwxr-xr-xazalea-core/src/game_type.rs24
-rwxr-xr-xazalea-core/src/lib.rs6
-rw-r--r--azalea-core/src/particle/mod.rs (renamed from azalea-protocol/src/mc_buf/definitions.rs)183
-rw-r--r--azalea-core/src/position.rs59
-rwxr-xr-xazalea-core/src/resource_location.rs26
-rwxr-xr-xazalea-core/src/serializable_uuid.rs22
-rw-r--r--azalea-core/src/slot.rs28
-rw-r--r--azalea-crypto/Cargo.toml1
-rw-r--r--azalea-crypto/src/lib.rs2
-rw-r--r--azalea-crypto/src/signing.rs16
-rw-r--r--azalea-entity/src/data.rs136
-rw-r--r--azalea-entity/src/lib.rs22
-rwxr-xr-xazalea-nbt/Cargo.toml1
-rwxr-xr-xazalea-nbt/src/decode.rs10
-rwxr-xr-xazalea-nbt/src/encode.rs7
-rwxr-xr-xazalea-nbt/src/lib.rs33
-rwxr-xr-xazalea-protocol/Cargo.toml10
-rwxr-xr-xazalea-protocol/packet-macros/src/lib.rs177
-rwxr-xr-xazalea-protocol/src/lib.rs6
-rw-r--r--azalea-protocol/src/packets/game/clientbound_add_player_packet.rs3
-rw-r--r--azalea-protocol/src/packets/game/clientbound_move_entity_pos_packet.rs5
-rw-r--r--azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs8
-rw-r--r--azalea-world/src/lib.rs16
-rw-r--r--bot/src/main.rs2
41 files changed, 805 insertions, 737 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c3e5a0ce..855b65de 100755
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -90,9 +90,19 @@ name = "azalea-brigadier"
version = "0.1.0"
[[package]]
+name = "azalea-buf"
+version = "0.1.0"
+dependencies = [
+ "buf-macros",
+ "byteorder",
+ "tokio",
+]
+
+[[package]]
name = "azalea-chat"
version = "0.1.0"
dependencies = [
+ "azalea-buf",
"azalea-language",
"lazy_static",
"serde",
@@ -117,6 +127,7 @@ dependencies = [
name = "azalea-core"
version = "0.1.0"
dependencies = [
+ "azalea-buf",
"azalea-chat",
"azalea-nbt",
"uuid",
@@ -127,6 +138,7 @@ name = "azalea-crypto"
version = "0.1.0"
dependencies = [
"aes",
+ "azalea-buf",
"cfb8",
"num-bigint",
"rand",
@@ -156,6 +168,7 @@ dependencies = [
name = "azalea-nbt"
version = "0.1.0"
dependencies = [
+ "azalea-buf",
"byteorder",
"criterion",
"flate2",
@@ -171,6 +184,7 @@ dependencies = [
"async-recursion",
"azalea-auth",
"azalea-brigadier",
+ "azalea-buf",
"azalea-chat",
"azalea-core",
"azalea-crypto",
@@ -251,6 +265,15 @@ dependencies = [
]
[[package]]
+name = "buf-macros"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "bumpalo"
version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index fc32b2d9..72019b5a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,6 +13,7 @@ members = [
"azalea-language",
"azalea-block",
"azalea-entity",
+ "azalea-buf",
]
[profile.release]
diff --git a/azalea-buf/Cargo.toml b/azalea-buf/Cargo.toml
new file mode 100644
index 00000000..79f9d64d
--- /dev/null
+++ b/azalea-buf/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+edition = "2021"
+name = "azalea-buf"
+version = "0.1.0"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+buf-macros = {path = "./buf-macros"}
+byteorder = "1.4.3"
+tokio = {version = "^1.19.2", features = ["io-util", "net", "macros"]}
diff --git a/azalea-buf/README.md b/azalea-buf/README.md
new file mode 100644
index 00000000..c988bcdb
--- /dev/null
+++ b/azalea-buf/README.md
@@ -0,0 +1,3 @@
+# Azalea Buf
+
+An implementation of Minecraft's FriendlyByteBuf. This is used frequently in the game for serialization and deserialization of data.
diff --git a/azalea-buf/buf-macros/Cargo.toml b/azalea-buf/buf-macros/Cargo.toml
new file mode 100644
index 00000000..fecf64ed
--- /dev/null
+++ b/azalea-buf/buf-macros/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+edition = "2021"
+name = "buf-macros"
+version = "0.1.0"
+
+[lib]
+proc-macro = true
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+proc-macro2 = "^1.0.36"
+quote = "^1.0.10"
+syn = "^1.0.82"
diff --git a/azalea-buf/buf-macros/src/lib.rs b/azalea-buf/buf-macros/src/lib.rs
new file mode 100644
index 00000000..3afeaeed
--- /dev/null
+++ b/azalea-buf/buf-macros/src/lib.rs
@@ -0,0 +1,177 @@
+use proc_macro::TokenStream;
+use quote::{quote, ToTokens};
+use syn::{self, parse_macro_input, Data, DeriveInput, FieldsNamed, Ident};
+
+fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
+ match data {
+ syn::Data::Struct(syn::DataStruct { fields, .. }) => {
+ let FieldsNamed { named, .. } = match fields {
+ syn::Fields::Named(f) => f,
+ _ => panic!("#[derive(McBuf)] can only be used on structs with named fields"),
+ };
+
+ let read_fields = named
+ .iter()
+ .map(|f| {
+ let field_name = &f.ident;
+ let field_type = &f.ty;
+ // do a different buf.write_* for each field depending on the type
+ // if it's a string, use buf.write_string
+ match field_type {
+ syn::Type::Path(_) => {
+ if f.attrs.iter().any(|a| a.path.is_ident("var")) {
+ quote! {
+ let #field_name = crate::McBufVarReadable::var_read_into(buf)?;
+ }
+ } else {
+ quote! {
+ let #field_name = crate::McBufReadable::read_into(buf)?;
+ }
+ }
+ }
+ _ => panic!(
+ "Error reading field {}: {}",
+ field_name.clone().unwrap(),
+ field_type.to_token_stream()
+ ),
+ }
+ })
+ .collect::<Vec<_>>();
+ let read_field_names = named.iter().map(|f| &f.ident).collect::<Vec<_>>();
+
+ quote! {
+ impl crate::McBufReadable for #ident {
+ fn read_into(buf: &mut impl std::io::Read) -> Result<Self, String> {
+ #(#read_fields)*
+ Ok(#ident {
+ #(#read_field_names: #read_field_names),*
+ })
+ }
+ }
+ }
+ }
+ syn::Data::Enum(syn::DataEnum { variants, .. }) => {
+ let mut match_contents = quote!();
+ let mut variant_discrim: u32 = 0;
+ for variant in variants {
+ let variant_name = &variant.ident;
+ match &variant.discriminant.as_ref() {
+ Some(d) => {
+ variant_discrim = match &d.1 {
+ syn::Expr::Lit(e) => match &e.lit {
+ syn::Lit::Int(i) => i.base10_parse().unwrap(),
+ _ => panic!("Error parsing enum discriminant"),
+ },
+ _ => panic!("Error parsing enum discriminant"),
+ }
+ }
+ None => {
+ variant_discrim += 1;
+ }
+ }
+ match_contents.extend(quote! {
+ #variant_discrim => Ok(Self::#variant_name),
+ });
+ }
+
+ quote! {
+ impl crate::McBufReadable for #ident {
+ fn read_into(buf: &mut impl std::io::Read) -> Result<Self, String>
+ {
+ let id = crate::McBufVarReadable::var_read_into(buf)?;
+ match id {
+ #match_contents
+ _ => Err(format!("Unknown enum variant {}", id)),
+ }
+ }
+ }
+ }
+ }
+ _ => panic!("#[derive(McBuf)] can only be used on structs"),
+ }
+}
+
+fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
+ match data {
+ syn::Data::Struct(syn::DataStruct { fields, .. }) => {
+ let FieldsNamed { named, .. } = match fields {
+ syn::Fields::Named(f) => f,
+ _ => panic!("#[derive(McBuf)] can only be used on structs with named fields"),
+ };
+
+ let write_fields = named
+ .iter()
+ .map(|f| {
+ let field_name = &f.ident;
+ let field_type = &f.ty;
+ // do a different buf.write_* for each field depending on the type
+ // if it's a string, use buf.write_string
+ match field_type {
+ syn::Type::Path(_) => {
+ if f.attrs.iter().any(|attr| attr.path.is_ident("var")) {
+ quote! {
+ crate::McBufVarWritable::var_write_into(&self.#field_name, buf)?;
+ }
+ } else {
+ quote! {
+ crate::McBufWritable::write_into(&self.#field_name, buf)?;
+ }
+ }
+ }
+ _ => panic!(
+ "Error writing field {}: {}",
+ field_name.clone().unwrap(),
+ field_type.to_token_stream()
+ ),
+ }
+ })
+ .collect::<Vec<_>>();
+
+ quote! {
+ impl crate::McBufWritable for #ident {
+ fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
+ #(#write_fields)*
+ Ok(())
+ }
+ }
+ }
+ }
+ syn::Data::Enum(syn::DataEnum { .. }) => {
+ quote! {
+ impl crate::McBufWritable for #ident {
+ fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
+ crate::Writable::write_varint(buf, *self as i32)
+ }
+ }
+ }
+ }
+ _ => panic!("#[derive(McBuf)] can only be used on structs"),
+ }
+}
+
+#[proc_macro_derive(McBufReadable, attributes(var))]
+pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream {
+ let DeriveInput { ident, data, .. } = parse_macro_input!(input);
+
+ create_impl_mcbufreadable(&ident, &data).into()
+}
+
+#[proc_macro_derive(McBufWritable, attributes(var))]
+pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream {
+ let DeriveInput { ident, data, .. } = parse_macro_input!(input);
+
+ create_impl_mcbufwritable(&ident, &data).into()
+}
+
+#[proc_macro_derive(McBuf, attributes(var))]
+pub fn derive_mcbuf(input: TokenStream) -> TokenStream {
+ let DeriveInput { ident, data, .. } = parse_macro_input!(input);
+
+ let writable = create_impl_mcbufwritable(&ident, &data);
+ let readable = create_impl_mcbufreadable(&ident, &data);
+ quote! {
+ #writable
+ #readable
+ }
+ .into()
+}
diff --git a/azalea-buf/src/definitions.rs b/azalea-buf/src/definitions.rs
new file mode 100644
index 00000000..e5d8e0c0
--- /dev/null
+++ b/azalea-buf/src/definitions.rs
@@ -0,0 +1,39 @@
+use buf_macros::McBuf;
+use std::ops::Deref;
+
+/// A Vec<u8> that isn't prefixed by a VarInt with the size.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct UnsizedByteArray(Vec<u8>);
+
+impl Deref for UnsizedByteArray {
+ type Target = Vec<u8>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl From<Vec<u8>> for UnsizedByteArray {
+ fn from(vec: Vec<u8>) -> Self {
+ Self(vec)
+ }
+}
+
+impl From<&str> for UnsizedByteArray {
+ fn from(s: &str) -> Self {
+ Self(s.as_bytes().to_vec())
+ }
+}
+
+/// Represents Java's BitSet, a list of bits.
+#[derive(Debug, Clone, PartialEq, Eq, Hash, McBuf)]
+pub struct BitSet {
+ data: Vec<u64>,
+}
+
+// the Index trait requires us to return a reference, but we can't do that
+impl BitSet {
+ pub fn index(&self, index: usize) -> bool {
+ (self.data[index / 64] & (1u64 << (index % 64))) != 0
+ }
+}
diff --git a/azalea-protocol/src/mc_buf/mod.rs b/azalea-buf/src/lib.rs
index 548ba7c2..2ba17ac2 100644
--- a/azalea-protocol/src/mc_buf/mod.rs
+++ b/azalea-buf/src/lib.rs
@@ -1,10 +1,13 @@
//! Utilities for reading and writing for the Minecraft protocol
+#![feature(min_specialization)]
+#![feature(arbitrary_enum_discriminant)]
+
mod definitions;
mod read;
mod write;
-pub use definitions::{BitSet, EntityMetadata, ParticleData, UnsizedByteArray};
+pub use definitions::*;
pub use read::{read_varint_async, McBufReadable, McBufVarReadable, Readable};
pub use write::{McBufVarWritable, McBufWritable, Writable};
@@ -12,14 +15,9 @@ pub use write::{McBufVarWritable, McBufWritable, Writable};
const MAX_STRING_LENGTH: u16 = 32767;
// const MAX_COMPONENT_STRING_LENGTH: u32 = 262144;
-// TODO: maybe get rid of the readable/writable traits so there's not two ways to do the same thing and improve McBufReadable/McBufWritable
-
-// TODO: have a definitions.rs in mc_buf that contains UnsizedByteArray and BitSet
-
#[cfg(test)]
mod tests {
use super::*;
- use azalea_core::resource_location::ResourceLocation;
use std::{collections::HashMap, io::Cursor};
#[test]
@@ -181,33 +179,6 @@ mod tests {
}
#[test]
- fn test_nbt() {
- let mut buf = Vec::new();
- buf.write_nbt(&azalea_nbt::Tag::Compound(HashMap::from_iter(vec![(
- "hello world".to_string(),
- azalea_nbt::Tag::Compound(HashMap::from_iter(vec![(
- "name".to_string(),
- azalea_nbt::Tag::String("Bananrama".to_string()),
- )])),
- )])))
- .unwrap();
-
- let mut buf = Cursor::new(buf);
-
- let result = buf.read_nbt().unwrap();
- assert_eq!(
- result,
- azalea_nbt::Tag::Compound(HashMap::from_iter(vec![(
- "hello world".to_string(),
- azalea_nbt::Tag::Compound(HashMap::from_iter(vec![(
- "name".to_string(),
- azalea_nbt::Tag::String("Bananrama".to_string()),
- )])),
- )]))
- );
- }
-
- #[test]
fn test_long() {
let mut buf = Vec::new();
buf.write_long(123456).unwrap();
@@ -216,18 +187,4 @@ mod tests {
assert_eq!(buf.read_long().unwrap(), 123456);
}
-
- #[test]
- fn test_resource_location() {
- let mut buf = Vec::new();
- buf.write_resource_location(&ResourceLocation::new("minecraft:dirt").unwrap())
- .unwrap();
-
- let mut buf = Cursor::new(buf);
-
- assert_eq!(
- buf.read_resource_location().unwrap(),
- ResourceLocation::new("minecraft:dirt").unwrap()
- );
- }
}
diff --git a/azalea-protocol/src/mc_buf/read.rs b/azalea-buf/src/read.rs
index ac8d5ccb..569a5b1d 100644
--- a/azalea-protocol/src/mc_buf/read.rs
+++ b/azalea-buf/src/read.rs
@@ -1,16 +1,9 @@
use super::{UnsizedByteArray, MAX_STRING_LENGTH};
-use azalea_chat::component::Component;
-use azalea_core::{
- difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
- serializable_uuid::SerializableUuid, BlockPos, ChunkSectionPos, Direction, GlobalPos, Slot,
- SlotData,
-};
-use azalea_crypto::SaltSignaturePair;
use byteorder::{ReadBytesExt, BE};
-use serde::Deserialize;
use std::{collections::HashMap, hash::Hash, io::Read};
use tokio::io::{AsyncRead, AsyncReadExt};
-use uuid::Uuid;
+
+// TODO: get rid of Readable and use McBufReadable everywhere
pub trait Readable {
fn read_int_id_list(&mut self) -> Result<Vec<i32>, String>;
@@ -25,13 +18,10 @@ pub trait Readable {
fn read_byte(&mut self) -> Result<u8, String>;
fn read_int(&mut self) -> Result<i32, String>;
fn read_boolean(&mut self) -> Result<bool, String>;
- fn read_nbt(&mut self) -> Result<azalea_nbt::Tag, String>;
fn read_long(&mut self) -> Result<i64, String>;
- fn read_resource_location(&mut self) -> Result<ResourceLocation, String>;
fn read_short(&mut self) -> Result<i16, String>;
fn read_float(&mut self) -> Result<f32, String>;
fn read_double(&mut self) -> Result<f64, String>;
- fn read_uuid(&mut self) -> Result<Uuid, String>;
}
impl<R> Readable for R
@@ -160,14 +150,6 @@ where
}
}
- fn read_nbt(&mut self) -> Result<azalea_nbt::Tag, String> {
- match azalea_nbt::Tag::read(self) {
- Ok(r) => Ok(r),
- // Err(e) => Err(e.to_string()),
- Err(e) => Err(e.to_string()).unwrap(),
- }
- }
-
fn read_long(&mut self) -> Result<i64, String> {
match self.read_i64::<BE>() {
Ok(r) => Ok(r),
@@ -175,13 +157,6 @@ where
}
}
- fn read_resource_location(&mut self) -> Result<ResourceLocation, String> {
- // get the resource location from the string
- let location_string = self.read_utf()?;
- let location = ResourceLocation::new(&location_string)?;
- Ok(location)
- }
-
fn read_short(&mut self) -> Result<i16, String> {
match self.read_i16::<BE>() {
Ok(r) => Ok(r),
@@ -202,15 +177,6 @@ where
Err(_) => Err("Error reading double".to_string()),
}
}
-
- fn read_uuid(&mut self) -> Result<Uuid, String> {
- Ok(Uuid::from_int_array([
- Readable::read_int(self)? as u32,
- Readable::read_int(self)? as u32,
- Readable::read_int(self)? as u32,
- Readable::read_int(self)? as u32,
- ]))
- }
}
// fast varints modified from https://github.com/luojia65/mc-varint/blob/master/src/lib.rs#L67
@@ -319,12 +285,6 @@ impl McBufReadable for String {
}
}
-impl McBufReadable for ResourceLocation {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- buf.read_resource_location()
- }
-}
-
impl McBufReadable for u32 {
fn read_into(buf: &mut impl Read) -> Result<Self, String> {
Readable::read_int(buf).map(|i| i as u32)
@@ -408,18 +368,6 @@ impl McBufReadable for f64 {
}
}
-impl McBufReadable for GameType {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- GameType::from_id(buf.read_byte()?)
- }
-}
-
-impl McBufReadable for Option<GameType> {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- GameType::from_optional_id(buf.read_byte()? as i8)
- }
-}
-
impl<T: McBufReadable> McBufReadable for Option<T> {
default fn read_into(buf: &mut impl Read) -> Result<Self, String> {
let present = buf.read_boolean()?;
@@ -430,96 +378,3 @@ impl<T: McBufReadable> McBufReadable for Option<T> {
})
}
}
-
-impl McBufReadable for azalea_nbt::Tag {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- buf.read_nbt()
- }
-}
-
-impl McBufReadable for Difficulty {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- Ok(Difficulty::by_id(u8::read_into(buf)?))
- }
-}
-
-impl McBufReadable for Component {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- let string = buf.read_utf()?;
- let json: serde_json::Value = serde_json::from_str(string.as_str())
- .map_err(|_| "Component isn't valid JSON".to_string())?;
- let component = Component::deserialize(json).map_err(|e| e.to_string())?;
- Ok(component)
- }
-}
-
-impl McBufReadable for Slot {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- let present = buf.read_boolean()?;
- if !present {
- return Ok(Slot::Empty);
- }
- let id = buf.read_varint()?;
- let count = buf.read_byte()?;
- let nbt = buf.read_nbt()?;
- Ok(Slot::Present(SlotData { id, count, nbt }))
- }
-}
-
-impl McBufReadable for Uuid {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- buf.read_uuid()
- }
-}
-
-impl McBufReadable for BlockPos {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- let val = u64::read_into(buf)?;
- let x = (val >> 38) as i32;
- let y = (val & 0xFFF) as i32;
- let z = ((val >> 12) & 0x3FFFFFF) as i32;
- Ok(BlockPos { x, y, z })
- }
-}
-
-impl McBufReadable for GlobalPos {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- Ok(GlobalPos {
- dimension: ResourceLocation::read_into(buf)?,
- pos: BlockPos::read_into(buf)?,
- })
- }
-}
-
-impl McBufReadable for Direction {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- match buf.read_varint()? {
- 0 => Ok(Self::Down),
- 1 => Ok(Self::Up),
- 2 => Ok(Self::North),
- 3 => Ok(Self::South),
- 4 => Ok(Self::West),
- 5 => Ok(Self::East),
- _ => Err("Invalid direction".to_string()),
- }
- }
-}
-
-impl McBufReadable for ChunkSectionPos {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- let long = i64::read_into(buf)?;
- Ok(ChunkSectionPos {
- x: (long >> 42) as i32,
- y: (long << 44 >> 44) as i32,
- z: (long << 22 >> 42) as i32,
- })
- }
-}
-
-impl McBufReadable for SaltSignaturePair {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- let salt = u64::read_into(buf)?;
- let signature = Vec::<u8>::read_into(buf)?;
- Ok(SaltSignaturePair { salt, signature })
- }
-}
diff --git a/azalea-protocol/src/mc_buf/write.rs b/azalea-buf/src/write.rs
index 945477d0..fdf58203 100644
--- a/azalea-protocol/src/mc_buf/write.rs
+++ b/azalea-buf/src/write.rs
@@ -1,13 +1,8 @@
use super::{UnsizedByteArray, MAX_STRING_LENGTH};
-use azalea_chat::component::Component;
-use azalea_core::{
- difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
- serializable_uuid::SerializableUuid, BlockPos, ChunkSectionPos, Direction, GlobalPos, Slot,
-};
-use azalea_crypto::SaltSignaturePair;
use byteorder::{BigEndian, WriteBytesExt};
use std::{collections::HashMap, io::Write};
-use uuid::Uuid;
+
+// TODO: get rid of Writable and use McBufWritable everywhere
pub trait Writable: Write {
fn write_list<F, T>(&mut self, list: &[T], writer: F) -> Result<(), std::io::Error>
@@ -101,14 +96,6 @@ pub trait Writable: Write {
self.write_byte(if b { 1 } else { 0 })
}
- fn write_nbt(&mut self, nbt: &azalea_nbt::Tag) -> Result<(), std::io::Error>
- where
- Self: Sized,
- {
- nbt.write(self)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
- }
-
fn write_long(&mut self, n: i64) -> Result<(), std::io::Error> {
WriteBytesExt::write_i64::<BigEndian>(self, n)
}
@@ -120,25 +107,6 @@ pub trait Writable: Write {
fn write_double(&mut self, n: f64) -> Result<(), std::io::Error> {
WriteBytesExt::write_f64::<BigEndian>(self, n)
}
-
- fn write_resource_location(
- &mut self,
- location: &ResourceLocation,
- ) -> Result<(), std::io::Error> {
- self.write_utf(&location.to_string())
- }
-
- fn write_uuid(&mut self, uuid: &Uuid) -> Result<(), std::io::Error>
- where
- Self: Sized,
- {
- let [a, b, c, d] = uuid.to_int_array();
- a.write_into(self)?;
- b.write_into(self)?;
- c.write_into(self)?;
- d.write_into(self)?;
- Ok(())
- }
}
impl<W: Write + ?Sized> Writable for W {}
@@ -199,12 +167,6 @@ impl McBufWritable for String {
}
}
-impl McBufWritable for ResourceLocation {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- buf.write_resource_location(self)
- }
-}
-
impl McBufWritable for u32 {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
i16::write_into(&(*self as i16), buf)
@@ -220,7 +182,6 @@ impl McBufVarWritable for u32 {
impl McBufVarWritable for i64 {
fn var_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
let mut buffer = [0];
- let mut cnt = 0;
let mut value = *self;
while value != 0 {
buffer[0] = (value & 0b0111_1111) as u8;
@@ -228,7 +189,7 @@ impl McBufVarWritable for i64 {
if value != 0 {
buffer[0] |= 0b1000_0000;
}
- cnt += buf.write(&mut buffer)?;
+ buf.write(&mut buffer)?;
}
Ok(())
}
@@ -310,18 +271,6 @@ impl McBufWritable for f64 {
}
}
-impl McBufWritable for GameType {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- u8::write_into(&self.to_id(), buf)
- }
-}
-
-impl McBufWritable for Option<GameType> {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- buf.write_byte(GameType::to_optional_id(self) as u8)
- }
-}
-
impl<T: McBufWritable> McBufWritable for Option<T> {
default fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
if let Some(s) = self {
@@ -333,98 +282,3 @@ impl<T: McBufWritable> McBufWritable for Option<T> {
Ok(())
}
}
-
-impl McBufWritable for azalea_nbt::Tag {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- buf.write_nbt(self)
- }
-}
-
-impl McBufWritable for Difficulty {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- u8::write_into(&self.id(), buf)
- }
-}
-
-impl McBufWritable for Component {
- // async fn read_into(buf: &mut impl Read) -> Result<Self, String>
- // where
- // R: AsyncRead + std::marker::Unpin + std::marker::Send,
- // {
- // let string = buf.read_utf().await?;
- // let json: serde_json::Value = serde_json::from_str(string.as_str())
- // .map_err(|e| "Component isn't valid JSON".to_string())?;
- // let component = Component::deserialize(json).map_err(|e| e.to_string())?;
- // Ok(component)
- // }
- fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
- // component doesn't have serialize implemented yet
- todo!()
- }
-}
-
-impl McBufWritable for Slot {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- match self {
- Slot::Empty => buf.write_byte(0)?,
- Slot::Present(i) => {
- buf.write_varint(i.id)?;
- buf.write_byte(i.count)?;
- buf.write_nbt(&i.nbt)?;
- }
- }
-
- Ok(())
- }
-}
-
-impl McBufWritable for Uuid {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- buf.write_uuid(self)?;
-
- Ok(())
- }
-}
-
-impl McBufWritable for BlockPos {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- buf.write_long(
- (((self.x & 0x3FFFFFF) as i64) << 38)
- | (((self.z & 0x3FFFFFF) as i64) << 12)
- | ((self.y & 0xFFF) as i64),
- )
- }
-}
-
-impl McBufWritable for GlobalPos {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- ResourceLocation::write_into(&self.dimension, buf)?;
- BlockPos::write_into(&self.pos, buf)?;
-
- Ok(())
- }
-}
-
-impl McBufWritable for Direction {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- buf.write_varint(*self as i32)
- }
-}
-
-impl McBufWritable for ChunkSectionPos {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- let long = (((self.x & 0x3FFFFF) as i64) << 42)
- | (self.y & 0xFFFFF) as i64
- | (((self.z & 0x3FFFFF) as i64) << 20);
- long.write_into(buf)?;
- Ok(())
- }
-}
-
-impl McBufWritable for SaltSignaturePair {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- self.salt.write_into(buf)?;
- self.signature.write_into(buf)?;
- Ok(())
- }
-}
diff --git a/azalea-chat/Cargo.toml b/azalea-chat/Cargo.toml
index 192d3405..5b85f6c2 100755
--- a/azalea-chat/Cargo.toml
+++ b/azalea-chat/Cargo.toml
@@ -6,6 +6,7 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+azalea-buf = {path = "../azalea-buf"}
azalea-language = {path = "../azalea-language"}
lazy_static = "1.4.0"
serde = "^1.0.130"
diff --git a/azalea-chat/src/component.rs b/azalea-chat/src/component.rs
index 36709cc0..872a0a5c 100755
--- a/azalea-chat/src/component.rs
+++ b/azalea-chat/src/component.rs
@@ -264,3 +264,30 @@ impl<'de> Deserialize<'de> for Component {
Ok(component)
}
}
+
+impl McBufReadable for Component {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ let string = buf.read_utf()?;
+ let json: serde_json::Value = serde_json::from_str(string.as_str())
+ .map_err(|_| "Component isn't valid JSON".to_string())?;
+ let component = Component::deserialize(json).map_err(|e| e.to_string())?;
+ Ok(component)
+ }
+}
+
+impl McBufWritable for Component {
+ // async fn read_into(buf: &mut impl Read) -> Result<Self, String>
+ // where
+ // R: AsyncRead + std::marker::Unpin + std::marker::Send,
+ // {
+ // let string = buf.read_utf().await?;
+ // let json: serde_json::Value = serde_json::from_str(string.as_str())
+ // .map_err(|e| "Component isn't valid JSON".to_string())?;
+ // let component = Component::deserialize(json).map_err(|e| e.to_string())?;
+ // Ok(component)
+ // }
+ fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
+ // component doesn't have serialize implemented yet
+ todo!()
+ }
+}
diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs
index 828578de..a5259db9 100644
--- a/azalea-client/src/client.rs
+++ b/azalea-client/src/client.rs
@@ -1,5 +1,5 @@
use crate::{Account, Player};
-use azalea_core::{resource_location::ResourceLocation, ChunkPos};
+use azalea_core::{resource_location::ResourceLocation, ChunkPos, EntityPos};
use azalea_entity::Entity;
use azalea_protocol::{
connect::{GameConnection, HandshakeConnection},
@@ -387,6 +387,13 @@ impl Client {
}
GamePacket::ClientboundAddPlayerPacket(p) => {
println!("Got add player packet {:?}", p);
+ let entity = Entity::from(p);
+ state
+ .lock()?
+ .world
+ .as_mut()
+ .expect("World doesn't exist! We should've gotten a login packet by now.")
+ .add_entity(entity);
}
GamePacket::ClientboundInitializeBorderPacket(p) => {
println!("Got initialize border packet {:?}", p);
@@ -406,20 +413,18 @@ impl Client {
GamePacket::ClientboundSetExperiencePacket(p) => {
println!("Got set experience packet {:?}", p);
}
- GamePacket::ClientboundTeleportEntityPacket(_p) => {
- // println!("Got teleport entity packet {:?}", p);
- // let state_lock = state.lock()?;
-
- // let entity = state_lock
- // .world
- // .unwrap()
- // .entity_by_id(p.id)
- // .ok_or("Teleporting entity that doesn't exist.".to_string())?;
- // state_lock
- // .world
- // .as_mut()
- // .expect("World doesn't exist! We should've gotten a login packet by now.")
- // .move_entity(&mut entity, new_pos)
+ GamePacket::ClientboundTeleportEntityPacket(p) => {
+ let mut state_lock = state.lock()?;
+ let world = state_lock.world.as_mut().unwrap();
+
+ world.move_entity(
+ p.id,
+ EntityPos {
+ x: p.x,
+ y: p.y,
+ z: p.z,
+ },
+ )?;
}
GamePacket::ClientboundUpdateAdvancementsPacket(p) => {
println!("Got update advancements packet {:?}", p);
@@ -427,11 +432,21 @@ impl Client {
GamePacket::ClientboundRotateHeadPacket(_p) => {
// println!("Got rotate head packet {:?}", p);
}
- GamePacket::ClientboundMoveEntityPosPacket(_p) => {
+ GamePacket::ClientboundMoveEntityPosPacket(p) => {
// println!("Got move entity pos packet {:?}", p);
}
- GamePacket::ClientboundMoveEntityPosRotPacket(_p) => {
- // println!("Got move entity pos rot packet {:?}", p);
+ GamePacket::ClientboundMoveEntityPosRotPacket(p) => {
+ let mut state_lock = state.lock()?;
+ let world = state_lock.world.as_mut().unwrap();
+
+ world.move_entity(
+ p.entity_id,
+ EntityPos {
+ x: p.x,
+ y: p.y,
+ z: p.z,
+ },
+ )?;
}
GamePacket::ClientboundMoveEntityRotPacket(p) => {
println!("Got move entity rot packet {:?}", p);
diff --git a/azalea-core/Cargo.toml b/azalea-core/Cargo.toml
index 27112b21..470bc998 100755
--- a/azalea-core/Cargo.toml
+++ b/azalea-core/Cargo.toml
@@ -6,6 +6,7 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+azalea-buf = {path = "../azalea-buf"}
azalea-chat = {path = "../azalea-chat"}
azalea-nbt = {path = "../azalea-nbt"}
uuid = "^1.1.2"
diff --git a/azalea-core/src/delta.rs b/azalea-core/src/delta.rs
new file mode 100644
index 00000000..32517e0d
--- /dev/null
+++ b/azalea-core/src/delta.rs
@@ -0,0 +1,26 @@
+/// Only works for up to 8 blocks
+#[derive(Clone, Debug, McBuf)]
+pub struct PositionDelta {
+ xa: i16,
+ ya: i16,
+ za: i16,
+}
+
+impl PositionDelta {
+ pub fn float(&self) -> (f64, f64, f64) {
+ (
+ (self.xa as f64) / 4096.0,
+ (self.ya as f64) / 4096.0,
+ (self.za as f64) / 4096.0,
+ )
+ }
+}
+
+impl EntityPos {
+ pub fn apply_delta(&mut self, delta: &PositionDelta) {
+ let (x, y, z) = delta.float();
+ self.x += x;
+ self.y += y;
+ self.z += z;
+ }
+}
diff --git a/azalea-core/src/difficulty.rs b/azalea-core/src/difficulty.rs
index 5d869325..7568f8e2 100755
--- a/azalea-core/src/difficulty.rs
+++ b/azalea-core/src/difficulty.rs
@@ -61,6 +61,18 @@ impl Difficulty {
}
}
+impl McBufReadable for Difficulty {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ Ok(Difficulty::by_id(u8::read_into(buf)?))
+ }
+}
+
+impl McBufWritable for Difficulty {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ u8::write_into(&self.id(), buf)
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/azalea-core/src/direction.rs b/azalea-core/src/direction.rs
index 721f21a0..bb655bdb 100644
--- a/azalea-core/src/direction.rs
+++ b/azalea-core/src/direction.rs
@@ -1,4 +1,4 @@
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, McBuf)]
pub enum Direction {
Down = 0,
Up = 1,
diff --git a/azalea-core/src/game_type.rs b/azalea-core/src/game_type.rs
index f5b9fb38..963048dd 100755
--- a/azalea-core/src/game_type.rs
+++ b/azalea-core/src/game_type.rs
@@ -71,3 +71,27 @@ impl GameType {
}
}
}
+
+impl McBufReadable for GameType {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ GameType::from_id(buf.read_byte()?)
+ }
+}
+
+impl McBufReadable for Option<GameType> {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ GameType::from_optional_id(buf.read_byte()? as i8)
+ }
+}
+
+impl McBufWritable for GameType {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ u8::write_into(&self.to_id(), buf)
+ }
+}
+
+impl McBufWritable for Option<GameType> {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ buf.write_byte(GameType::to_optional_id(self) as u8)
+ }
+}
diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs
index a2632871..41c901c8 100755
--- a/azalea-core/src/lib.rs
+++ b/azalea-core/src/lib.rs
@@ -15,3 +15,9 @@ pub use position::*;
mod direction;
pub use direction::Direction;
+
+mod delta;
+pub use delta::*;
+
+mod particle;
+pub use particle::*;
diff --git a/azalea-protocol/src/mc_buf/definitions.rs b/azalea-core/src/particle/mod.rs
index 3867b3fc..fc815a0b 100644
--- a/azalea-protocol/src/mc_buf/definitions.rs
+++ b/azalea-core/src/particle/mod.rs
@@ -1,186 +1,3 @@
-use crate::mc_buf::read::{McBufReadable, Readable};
-use crate::mc_buf::write::{McBufWritable, Writable};
-use crate::mc_buf::McBufVarReadable;
-use azalea_chat::component::Component;
-use azalea_core::{BlockPos, Direction, Slot};
-use packet_macros::McBuf;
-use std::io::{Read, Write};
-use std::ops::Deref;
-use uuid::Uuid;
-
-/// A Vec<u8> that isn't prefixed by a VarInt with the size.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct UnsizedByteArray(Vec<u8>);
-
-impl Deref for UnsizedByteArray {
- type Target = Vec<u8>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl From<Vec<u8>> for UnsizedByteArray {
- fn from(vec: Vec<u8>) -> Self {
- Self(vec)
- }
-}
-
-impl From<&str> for UnsizedByteArray {
- fn from(s: &str) -> Self {
- Self(s.as_bytes().to_vec())
- }
-}
-
-/// Represents Java's BitSet, a list of bits.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, McBuf)]
-pub struct BitSet {
- data: Vec<u64>,
-}
-
-// the Index trait requires us to return a reference, but we can't do that
-impl BitSet {
- pub fn index(&self, index: usize) -> bool {
- (self.data[index / 64] & (1u64 << (index % 64))) != 0
- }
-}
-
-pub type EntityMetadata = Vec<EntityDataItem>;
-
-#[derive(Clone, Debug)]
-pub struct EntityDataItem {
- // we can't identify what the index is for here because we don't know the
- // entity type
- pub index: u8,
- pub value: EntityDataValue,
-}
-
-impl McBufReadable for Vec<EntityDataItem> {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- let mut metadata = Vec::new();
- loop {
- let index = buf.read_byte()?;
- if index == 0xff {
- break;
- }
- let value = EntityDataValue::read_into(buf)?;
- metadata.push(EntityDataItem { index, value });
- }
- Ok(metadata)
- }
-}
-
-impl McBufWritable for Vec<EntityDataItem> {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- for item in self {
- buf.write_byte(item.index)?;
- item.value.write_into(buf)?;
- }
- buf.write_byte(0xff)?;
- Ok(())
- }
-}
-
-#[derive(Clone, Debug)]
-pub enum EntityDataValue {
- Byte(u8),
- // varint
- Int(i32),
- Float(f32),
- String(String),
- Component(Component),
- OptionalComponent(Option<Component>),
- ItemStack(Slot),
- Boolean(bool),
- Rotations { x: f32, y: f32, z: f32 },
- BlockPos(BlockPos),
- OptionalBlockPos(Option<BlockPos>),
- Direction(Direction),
- OptionalUuid(Option<Uuid>),
- // 0 for absent (implies air); otherwise, a block state ID as per the global palette
- // this is a varint
- OptionalBlockState(Option<i32>),
- CompoundTag(azalea_nbt::Tag),
- Particle(Particle),
- VillagerData(VillagerData),
- // 0 for absent; 1 + actual value otherwise. Used for entity IDs.
- OptionalUnsignedInt(Option<u32>),
- Pose(Pose),
-}
-
-impl McBufReadable for EntityDataValue {
- fn read_into(buf: &mut impl Read) -> Result<Self, String> {
- let type_ = buf.read_varint()?;
- Ok(match type_ {
- 0 => EntityDataValue::Byte(buf.read_byte()?),
- 1 => EntityDataValue::Int(buf.read_varint()?),
- 2 => EntityDataValue::Float(buf.read_float()?),
- 3 => EntityDataValue::String(buf.read_utf()?),
- 4 => EntityDataValue::Component(Component::read_into(buf)?),
- 5 => EntityDataValue::OptionalComponent(Option::<Component>::read_into(buf)?),
- 6 => EntityDataValue::ItemStack(Slot::read_into(buf)?),
- 7 => EntityDataValue::Boolean(buf.read_boolean()?),
- 8 => EntityDataValue::Rotations {
- x: buf.read_float()?,
- y: buf.read_float()?,
- z: buf.read_float()?,
- },
- 9 => EntityDataValue::BlockPos(BlockPos::read_into(buf)?),
- 10 => EntityDataValue::OptionalBlockPos(Option::<BlockPos>::read_into(buf)?),
- 11 => EntityDataValue::Direction(Direction::read_into(buf)?),
- 12 => EntityDataValue::OptionalUuid(Option::<Uuid>::read_into(buf)?),
- 13 => EntityDataValue::OptionalBlockState({
- let val = i32::read_into(buf)?;
- if val == 0 {
- None
- } else {
- Some(val)
- }
- }),
- 14 => EntityDataValue::CompoundTag(azalea_nbt::Tag::read_into(buf)?),
- 15 => EntityDataValue::Particle(Particle::read_into(buf)?),
- 16 => EntityDataValue::VillagerData(VillagerData::read_into(buf)?),
- 17 => EntityDataValue::OptionalUnsignedInt({
- let val = buf.read_varint()?;
- if val == 0 {
- None
- } else {
- Some((val - 1) as u32)
- }
- }),
- 18 => EntityDataValue::Pose(Pose::read_into(buf)?),
- _ => return Err(format!("Unknown entity data type: {}", type_)),
- })
- }
-}
-
-impl McBufWritable for EntityDataValue {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- todo!();
- }
-}
-
-#[derive(Clone, Debug, Copy, McBuf)]
-pub enum Pose {
- Standing = 0,
- FallFlying = 1,
- Sleeping = 2,
- Swimming = 3,
- SpinAttack = 4,
- Sneaking = 5,
- LongJumping = 6,
- Dying = 7,
-}
-
-#[derive(Debug, Clone, McBuf)]
-pub struct VillagerData {
- #[var]
- type_: u32,
- #[var]
- profession: u32,
- #[var]
- level: u32,
-}
#[derive(Debug, Clone, McBuf)]
pub struct Particle {
diff --git a/azalea-core/src/position.rs b/azalea-core/src/position.rs
index 7b2c01da..9e7aca20 100644
--- a/azalea-core/src/position.rs
+++ b/azalea-core/src/position.rs
@@ -170,6 +170,65 @@ impl From<&EntityPos> for ChunkPos {
}
}
+impl McBufReadable for BlockPos {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ let val = u64::read_into(buf)?;
+ let x = (val >> 38) as i32;
+ let y = (val & 0xFFF) as i32;
+ let z = ((val >> 12) & 0x3FFFFFF) as i32;
+ Ok(BlockPos { x, y, z })
+ }
+}
+
+impl McBufReadable for GlobalPos {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ Ok(GlobalPos {
+ dimension: ResourceLocation::read_into(buf)?,
+ pos: BlockPos::read_into(buf)?,
+ })
+ }
+}
+
+impl McBufReadable for ChunkSectionPos {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ let long = i64::read_into(buf)?;
+ Ok(ChunkSectionPos {
+ x: (long >> 42) as i32,
+ y: (long << 44 >> 44) as i32,
+ z: (long << 22 >> 42) as i32,
+ })
+ }
+}
+
+impl McBufWritable for BlockPos {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ buf.write_long(
+ (((self.x & 0x3FFFFFF) as i64) << 38)
+ | (((self.z & 0x3FFFFFF) as i64) << 12)
+ | ((self.y & 0xFFF) as i64),
+ )
+ }
+}
+
+impl McBufWritable for GlobalPos {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ ResourceLocation::write_into(&self.dimension, buf)?;
+ BlockPos::write_into(&self.pos, buf)?;
+
+ Ok(())
+ }
+}
+
+impl McBufWritable for ChunkSectionPos {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ let long = (((self.x & 0x3FFFFF) as i64) << 42)
+ | (self.y & 0xFFFFF) as i64
+ | (((self.z & 0x3FFFFF) as i64) << 20);
+ long.write_into(buf)?;
+ Ok(())
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/azalea-core/src/resource_location.rs b/azalea-core/src/resource_location.rs
index cdf8f381..6807714b 100755
--- a/azalea-core/src/resource_location.rs
+++ b/azalea-core/src/resource_location.rs
@@ -42,6 +42,18 @@ impl std::fmt::Debug for ResourceLocation {
}
}
+impl McBufReadable for ResourceLocation {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ let location_string = self.read_utf()?;
+ ResourceLocation::new(&location_string)
+ }
+}
+impl McBufWritable for ResourceLocation {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ buf.write_utf(&self.to_string())
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -70,4 +82,18 @@ mod tests {
assert_eq!(r.namespace, "azalea");
assert_eq!(r.path, "");
}
+
+ #[test]
+ fn mcbuf_resource_location() {
+ let mut buf = Vec::new();
+ buf.write_resource_location(&ResourceLocation::new("minecraft:dirt").unwrap())
+ .unwrap();
+
+ let mut buf = Cursor::new(buf);
+
+ assert_eq!(
+ buf.read_resource_location().unwrap(),
+ ResourceLocation::new("minecraft:dirt").unwrap()
+ );
+ }
}
diff --git a/azalea-core/src/serializable_uuid.rs b/azalea-core/src/serializable_uuid.rs
index f8c03b60..2c7128ff 100755
--- a/azalea-core/src/serializable_uuid.rs
+++ b/azalea-core/src/serializable_uuid.rs
@@ -30,6 +30,28 @@ impl SerializableUuid for Uuid {
}
}
+impl McBufReadable for Uuid {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ Ok(Uuid::from_int_array([
+ Readable::read_int(self)? as u32,
+ Readable::read_int(self)? as u32,
+ Readable::read_int(self)? as u32,
+ Readable::read_int(self)? as u32,
+ ]))
+ }
+}
+
+impl McBufWritable for Uuid {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ let [a, b, c, d] = self.to_int_array();
+ a.write_into(buf)?;
+ b.write_into(buf)?;
+ c.write_into(buf)?;
+ d.write_into(buf)?;
+ Ok(())
+ }
+}
+
#[cfg(tests)]
mod tests {
use super::*;
diff --git a/azalea-core/src/slot.rs b/azalea-core/src/slot.rs
index 5e42f558..e3b78289 100644
--- a/azalea-core/src/slot.rs
+++ b/azalea-core/src/slot.rs
@@ -12,3 +12,31 @@ pub struct SlotData {
pub count: u8,
pub nbt: azalea_nbt::Tag,
}
+
+impl McBufReadable for Slot {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ let present = buf.read_boolean()?;
+ if !present {
+ return Ok(Slot::Empty);
+ }
+ let id = buf.read_varint()?;
+ let count = buf.read_byte()?;
+ let nbt = buf.read_nbt()?;
+ Ok(Slot::Present(SlotData { id, count, nbt }))
+ }
+}
+
+impl McBufWritable for Slot {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ match self {
+ Slot::Empty => buf.write_byte(0)?,
+ Slot::Present(i) => {
+ buf.write_varint(i.id)?;
+ buf.write_byte(i.count)?;
+ buf.write_nbt(&i.nbt)?;
+ }
+ }
+
+ Ok(())
+ }
+}
diff --git a/azalea-crypto/Cargo.toml b/azalea-crypto/Cargo.toml
index 2532bff9..ee652565 100644
--- a/azalea-crypto/Cargo.toml
+++ b/azalea-crypto/Cargo.toml
@@ -7,6 +7,7 @@ version = "0.1.0"
[dependencies]
aes = "0.8.1"
+azalea-buf = {path = "../azalea-buf"}
cfb8 = "0.8.1"
num-bigint = "^0.4.3"
rand = {version = "^0.8.4", features = ["getrandom"]}
diff --git a/azalea-crypto/src/lib.rs b/azalea-crypto/src/lib.rs
index a5e797e8..85705883 100644
--- a/azalea-crypto/src/lib.rs
+++ b/azalea-crypto/src/lib.rs
@@ -79,6 +79,8 @@ pub fn decrypt_packet(cipher: &mut Aes128CfbDec, packet: &mut [u8]) {
cipher.decrypt_blocks_inout_mut(chunks);
}
+
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/azalea-crypto/src/signing.rs b/azalea-crypto/src/signing.rs
index 21cd813a..a5280a18 100644
--- a/azalea-crypto/src/signing.rs
+++ b/azalea-crypto/src/signing.rs
@@ -3,3 +3,19 @@ pub struct SaltSignaturePair {
pub salt: u64,
pub signature: Vec<u8>,
}
+
+impl McBufReadable for SaltSignaturePair {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ let salt = u64::read_into(buf)?;
+ let signature = Vec::<u8>::read_into(buf)?;
+ Ok(SaltSignaturePair { salt, signature })
+ }
+}
+
+impl McBufWritable for SaltSignaturePair {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ self.salt.write_into(buf)?;
+ self.signature.write_into(buf)?;
+ Ok(())
+ }
+}
diff --git a/azalea-entity/src/data.rs b/azalea-entity/src/data.rs
new file mode 100644
index 00000000..ddc6f57b
--- /dev/null
+++ b/azalea-entity/src/data.rs
@@ -0,0 +1,136 @@
+pub type EntityMetadata = Vec<EntityDataItem>;
+
+#[derive(Clone, Debug)]
+pub struct EntityDataItem {
+ // we can't identify what the index is for here because we don't know the
+ // entity type
+ pub index: u8,
+ pub value: EntityDataValue,
+}
+
+impl McBufReadable for Vec<EntityDataItem> {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ let mut metadata = Vec::new();
+ loop {
+ let index = u8::read_into(buf)?;
+ if index == 0xff {
+ break;
+ }
+ let value = EntityDataValue::read_into(buf)?;
+ metadata.push(EntityDataItem { index, value });
+ }
+ Ok(metadata)
+ }
+}
+
+impl McBufWritable for Vec<EntityDataItem> {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ for item in self {
+ buf.write_byte(item.index)?;
+ item.value.write_into(buf)?;
+ }
+ buf.write_byte(0xff)?;
+ Ok(())
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum EntityDataValue {
+ Byte(u8),
+ // varint
+ Int(i32),
+ Float(f32),
+ String(String),
+ Component(Component),
+ OptionalComponent(Option<Component>),
+ ItemStack(Slot),
+ Boolean(bool),
+ Rotations { x: f32, y: f32, z: f32 },
+ BlockPos(BlockPos),
+ OptionalBlockPos(Option<BlockPos>),
+ Direction(Direction),
+ OptionalUuid(Option<Uuid>),
+ // 0 for absent (implies air); otherwise, a block state ID as per the global palette
+ // this is a varint
+ OptionalBlockState(Option<i32>),
+ CompoundTag(azalea_nbt::Tag),
+ Particle(Particle),
+ VillagerData(VillagerData),
+ // 0 for absent; 1 + actual value otherwise. Used for entity IDs.
+ OptionalUnsignedInt(Option<u32>),
+ Pose(Pose),
+}
+
+impl McBufReadable for EntityDataValue {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ let type_ = buf.read_varint()?;
+ Ok(match type_ {
+ 0 => EntityDataValue::Byte(buf.read_byte()?),
+ 1 => EntityDataValue::Int(buf.read_varint()?),
+ 2 => EntityDataValue::Float(buf.read_float()?),
+ 3 => EntityDataValue::String(buf.read_utf()?),
+ 4 => EntityDataValue::Component(Component::read_into(buf)?),
+ 5 => EntityDataValue::OptionalComponent(Option::<Component>::read_into(buf)?),
+ 6 => EntityDataValue::ItemStack(Slot::read_into(buf)?),
+ 7 => EntityDataValue::Boolean(buf.read_boolean()?),
+ 8 => EntityDataValue::Rotations {
+ x: buf.read_float()?,
+ y: buf.read_float()?,
+ z: buf.read_float()?,
+ },
+ 9 => EntityDataValue::BlockPos(BlockPos::read_into(buf)?),
+ 10 => EntityDataValue::OptionalBlockPos(Option::<BlockPos>::read_into(buf)?),
+ 11 => EntityDataValue::Direction(Direction::read_into(buf)?),
+ 12 => EntityDataValue::OptionalUuid(Option::<Uuid>::read_into(buf)?),
+ 13 => EntityDataValue::OptionalBlockState({
+ let val = i32::read_into(buf)?;
+ if val == 0 {
+ None
+ } else {
+ Some(val)
+ }
+ }),
+ 14 => EntityDataValue::CompoundTag(azalea_nbt::Tag::read_into(buf)?),
+ 15 => EntityDataValue::Particle(Particle::read_into(buf)?),
+ 16 => EntityDataValue::VillagerData(VillagerData::read_into(buf)?),
+ 17 => EntityDataValue::OptionalUnsignedInt({
+ let val = buf.read_varint()?;
+ if val == 0 {
+ None
+ } else {
+ Some((val - 1) as u32)
+ }
+ }),
+ 18 => EntityDataValue::Pose(Pose::read_into(buf)?),
+ _ => return Err(format!("Unknown entity data type: {}", type_)),
+ })
+ }
+}
+
+impl McBufWritable for EntityDataValue {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ todo!();
+ }
+}
+
+#[derive(Clone, Debug, Copy, McBuf)]
+pub enum Pose {
+ Standing = 0,
+ FallFlying = 1,
+ Sleeping = 2,
+ Swimming = 3,
+ SpinAttack = 4,
+ Sneaking = 5,
+ LongJumping = 6,
+ Dying = 7,
+}
+
+#[derive(Debug, Clone, McBuf)]
+pub struct VillagerData {
+ #[var]
+ type_: u32,
+ #[var]
+ profession: u32,
+ #[var]
+ level: u32,
+}
diff --git a/azalea-entity/src/lib.rs b/azalea-entity/src/lib.rs
index d32a1a96..2283142f 100644
--- a/azalea-entity/src/lib.rs
+++ b/azalea-entity/src/lib.rs
@@ -1,6 +1,11 @@
+mod data;
+
use azalea_core::EntityPos;
#[cfg(feature = "protocol")]
-use azalea_protocol::packets::game::clientbound_add_entity_packet::ClientboundAddEntityPacket;
+use azalea_protocol::packets::game::{
+ clientbound_add_entity_packet::ClientboundAddEntityPacket,
+ clientbound_add_player_packet::ClientboundAddPlayerPacket,
+};
use uuid::Uuid;
#[derive(Default, Debug)]
@@ -38,6 +43,21 @@ impl From<&ClientboundAddEntityPacket> for Entity {
}
}
+#[cfg(feature = "protocol")]
+impl From<&ClientboundAddPlayerPacket> for Entity {
+ fn from(p: &ClientboundAddPlayerPacket) -> Self {
+ Self {
+ id: p.id,
+ uuid: p.uuid,
+ pos: EntityPos {
+ x: p.x,
+ y: p.y,
+ z: p.z,
+ },
+ }
+ }
+}
+
// #[cfg(test)]
// mod tests {
// #[test]
diff --git a/azalea-nbt/Cargo.toml b/azalea-nbt/Cargo.toml
index ad466e1f..992d242a 100755
--- a/azalea-nbt/Cargo.toml
+++ b/azalea-nbt/Cargo.toml
@@ -6,6 +6,7 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+azalea-buf = {path = "../azalea-buf"}
byteorder = "1.4.3"
flate2 = "1.0.23"
num-derive = "^0.3.3"
diff --git a/azalea-nbt/src/decode.rs b/azalea-nbt/src/decode.rs
index 7f2ca754..73cd613e 100755
--- a/azalea-nbt/src/decode.rs
+++ b/azalea-nbt/src/decode.rs
@@ -136,3 +136,13 @@ impl Tag {
Tag::read(&mut gz)
}
}
+
+impl McBufReadable for Tag {
+ fn read_into(buf: &mut impl Read) -> Result<Self, String> {
+ match Tag::read(self) {
+ Ok(r) => Ok(r),
+ // Err(e) => Err(e.to_string()),
+ Err(e) => Err(e.to_string()).unwrap(),
+ }
+ }
+}
diff --git a/azalea-nbt/src/encode.rs b/azalea-nbt/src/encode.rs
index fb5585b3..17d20270 100755
--- a/azalea-nbt/src/encode.rs
+++ b/azalea-nbt/src/encode.rs
@@ -217,3 +217,10 @@ impl Tag {
self.write(&mut encoder)
}
}
+
+impl McBufWritable for Tag {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ self.write(buf)
+ .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
+ }
+}
diff --git a/azalea-nbt/src/lib.rs b/azalea-nbt/src/lib.rs
index d14fd929..8cca1f2b 100755
--- a/azalea-nbt/src/lib.rs
+++ b/azalea-nbt/src/lib.rs
@@ -5,3 +5,36 @@ mod tag;
pub use error::Error;
pub use tag::Tag;
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::{collections::HashMap, io::Cursor};
+
+ #[test]
+ fn mcbuf_nbt() {
+ let mut buf = Vec::new();
+ buf.write_nbt(&Tag::Compound(HashMap::from_iter(vec![(
+ "hello world".to_string(),
+ Tag::Compound(HashMap::from_iter(vec![(
+ "name".to_string(),
+ Tag::String("Bananrama".to_string()),
+ )])),
+ )])))
+ .unwrap();
+
+ let mut buf = Cursor::new(buf);
+
+ let result = buf.read_nbt().unwrap();
+ assert_eq!(
+ result,
+ Tag::Compound(HashMap::from_iter(vec![(
+ "hello world".to_string(),
+ Tag::Compound(HashMap::from_iter(vec![(
+ "name".to_string(),
+ Tag::String("Bananrama".to_string()),
+ )])),
+ )]))
+ );
+ }
+}
diff --git a/azalea-protocol/Cargo.toml b/azalea-protocol/Cargo.toml
index f1640a01..dadb212c 100755
--- a/azalea-protocol/Cargo.toml
+++ b/azalea-protocol/Cargo.toml
@@ -6,12 +6,13 @@ version = "0.1.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-async-compression = {version = "^0.3.8", features = ["tokio", "zlib"]}
+async-compression = {version = "^0.3.8", features = ["tokio", "zlib"], optional = true}
async-recursion = "^0.3.2"
azalea-auth = {path = "../azalea-auth"}
azalea-brigadier = {path = "../azalea-brigadier"}
+azalea-buf = {path = "../azalea-buf"}
azalea-chat = {path = "../azalea-chat"}
-azalea-core = {path = "../azalea-core"}
+azalea-core = {path = "../azalea-core", optional = true}
azalea-crypto = {path = "../azalea-crypto"}
azalea-nbt = {path = "../azalea-nbt"}
byteorder = "^1.4.3"
@@ -27,3 +28,8 @@ tokio = {version = "^1.19.2", features = ["io-util", "net", "macros"]}
tokio-util = "^0.6.9"
trust-dns-resolver = "^0.20.3"
uuid = "^1.1.2"
+
+[features]
+connecting = []
+default = ["packets"]
+packets = ["connecting", "dep:async-compression", "dep:azalea-core"]
diff --git a/azalea-protocol/packet-macros/src/lib.rs b/azalea-protocol/packet-macros/src/lib.rs
index 5ea69a62..56b5dc52 100755
--- a/azalea-protocol/packet-macros/src/lib.rs
+++ b/azalea-protocol/packet-macros/src/lib.rs
@@ -6,180 +6,6 @@ use syn::{
parse_macro_input, Data, DeriveInput, FieldsNamed, Ident, LitInt, Token,
};
-fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
- match data {
- syn::Data::Struct(syn::DataStruct { fields, .. }) => {
- let FieldsNamed { named, .. } = match fields {
- syn::Fields::Named(f) => f,
- _ => panic!("#[derive(*Packet)] can only be used on structs with named fields"),
- };
-
- let read_fields = named
- .iter()
- .map(|f| {
- let field_name = &f.ident;
- let field_type = &f.ty;
- // do a different buf.write_* for each field depending on the type
- // if it's a string, use buf.write_string
- match field_type {
- syn::Type::Path(_) => {
- if f.attrs.iter().any(|a| a.path.is_ident("var")) {
- quote! {
- let #field_name = crate::mc_buf::McBufVarReadable::var_read_into(buf)?;
- }
- } else {
- quote! {
- let #field_name = crate::mc_buf::McBufReadable::read_into(buf)?;
- }
- }
- }
- _ => panic!(
- "Error reading field {}: {}",
- field_name.clone().unwrap(),
- field_type.to_token_stream()
- ),
- }
- })
- .collect::<Vec<_>>();
- let read_field_names = named.iter().map(|f| &f.ident).collect::<Vec<_>>();
-
- quote! {
- impl crate::mc_buf::McBufReadable for #ident {
- fn read_into(buf: &mut impl std::io::Read) -> Result<Self, String> {
- #(#read_fields)*
- Ok(#ident {
- #(#read_field_names: #read_field_names),*
- })
- }
- }
- }
- }
- syn::Data::Enum(syn::DataEnum { variants, .. }) => {
- let mut match_contents = quote!();
- let mut variant_discrim: u32 = 0;
- for variant in variants {
- let variant_name = &variant.ident;
- match &variant.discriminant.as_ref() {
- Some(d) => {
- variant_discrim = match &d.1 {
- syn::Expr::Lit(e) => match &e.lit {
- syn::Lit::Int(i) => i.base10_parse().unwrap(),
- _ => panic!("Error parsing enum discriminant"),
- },
- _ => panic!("Error parsing enum discriminant"),
- }
- }
- None => {
- variant_discrim += 1;
- }
- }
- match_contents.extend(quote! {
- #variant_discrim => Ok(Self::#variant_name),
- });
- }
-
- quote! {
- impl crate::mc_buf::McBufReadable for #ident {
- fn read_into(buf: &mut impl std::io::Read) -> Result<Self, String>
- {
- let id = crate::mc_buf::McBufVarReadable::var_read_into(buf)?;
- match id {
- #match_contents
- _ => Err(format!("Unknown enum variant {}", id)),
- }
- }
- }
- }
- }
- _ => panic!("#[derive(*Packet)] can only be used on structs"),
- }
-}
-
-fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
- match data {
- syn::Data::Struct(syn::DataStruct { fields, .. }) => {
- let FieldsNamed { named, .. } = match fields {
- syn::Fields::Named(f) => f,
- _ => panic!("#[derive(*Packet)] can only be used on structs with named fields"),
- };
-
- let write_fields = named
- .iter()
- .map(|f| {
- let field_name = &f.ident;
- let field_type = &f.ty;
- // do a different buf.write_* for each field depending on the type
- // if it's a string, use buf.write_string
- match field_type {
- syn::Type::Path(_) => {
- if f.attrs.iter().any(|attr| attr.path.is_ident("var")) {
- quote! {
- crate::mc_buf::McBufVarWritable::var_write_into(&self.#field_name, buf)?;
- }
- } else {
- quote! {
- crate::mc_buf::McBufWritable::write_into(&self.#field_name, buf)?;
- }
- }
- }
- _ => panic!(
- "Error writing field {}: {}",
- field_name.clone().unwrap(),
- field_type.to_token_stream()
- ),
- }
- })
- .collect::<Vec<_>>();
-
- quote! {
- impl crate::mc_buf::McBufWritable for #ident {
- fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
- #(#write_fields)*
- Ok(())
- }
- }
- }
- }
- syn::Data::Enum(syn::DataEnum { .. }) => {
- quote! {
- impl crate::mc_buf::McBufWritable for #ident {
- fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
- crate::mc_buf::Writable::write_varint(buf, *self as i32)
- }
- }
- }
- }
- _ => panic!("#[derive(*Packet)] can only be used on structs"),
- }
-}
-
-#[proc_macro_derive(McBufReadable, attributes(var))]
-pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream {
- let DeriveInput { ident, data, .. } = parse_macro_input!(input);
-
- create_impl_mcbufreadable(&ident, &data).into()
-}
-
-#[proc_macro_derive(McBufWritable, attributes(var))]
-pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream {
- let DeriveInput { ident, data, .. } = parse_macro_input!(input);
-
- create_impl_mcbufwritable(&ident, &data).into()
-}
-
-#[proc_macro_derive(McBuf, attributes(var))]
-pub fn derive_mcbuf(input: TokenStream) -> TokenStream {
- let DeriveInput { ident, data, .. } = parse_macro_input!(input);
-
- let writable = create_impl_mcbufwritable(&ident, &data);
- let readable = create_impl_mcbufreadable(&ident, &data);
- quote! {
- #writable
- #readable
- }
- .into()
-}
-
fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
@@ -192,9 +18,6 @@ fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> Toke
_ => panic!("#[derive(*Packet)] can only be used on structs with named fields"),
};
- let _mcbufreadable_impl = create_impl_mcbufreadable(&ident, &data);
- let _mcbufwritable_impl = create_impl_mcbufwritable(&ident, &data);
-
let contents = quote! {
impl #ident {
pub fn get(self) -> #state {
diff --git a/azalea-protocol/src/lib.rs b/azalea-protocol/src/lib.rs
index d7f75f00..cadbb437 100755
--- a/azalea-protocol/src/lib.rs
+++ b/azalea-protocol/src/lib.rs
@@ -1,13 +1,12 @@
//! This lib is responsible for parsing Minecraft packets.
-#![feature(min_specialization)]
-#![feature(arbitrary_enum_discriminant)]
-
use std::net::IpAddr;
use std::str::FromStr;
+#[cfg(feature = "connecting")]
pub mod connect;
pub mod mc_buf;
+#[cfg(feature = "packets")]
pub mod packets;
pub mod read;
pub mod resolver;
@@ -43,6 +42,7 @@ impl<'a> TryFrom<&'a str> for ServerAddress {
}
}
+#[cfg(feature = "connecting")]
pub async fn connect(address: ServerAddress) -> Result<(), Box<dyn std::error::Error>> {
let resolved_address = resolver::resolve_address(&address).await;
println!("Resolved address: {:?}", resolved_address);
diff --git a/azalea-protocol/src/packets/game/clientbound_add_player_packet.rs b/azalea-protocol/src/packets/game/clientbound_add_player_packet.rs
index f1947d09..4dae88a5 100644
--- a/azalea-protocol/src/packets/game/clientbound_add_player_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_add_player_packet.rs
@@ -1,10 +1,11 @@
use packet_macros::{GamePacket, McBuf};
use uuid::Uuid;
+/// This packet is sent by the server when a player comes into visible range, not when a player joins.
#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundAddPlayerPacket {
#[var]
- pub id: i32,
+ pub id: u32,
pub uuid: Uuid,
pub x: f64,
pub y: f64,
diff --git a/azalea-protocol/src/packets/game/clientbound_move_entity_pos_packet.rs b/azalea-protocol/src/packets/game/clientbound_move_entity_pos_packet.rs
index 0fc0104a..714917b7 100644
--- a/azalea-protocol/src/packets/game/clientbound_move_entity_pos_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_move_entity_pos_packet.rs
@@ -1,11 +1,10 @@
+use azalea_core::EntityPos;
use packet_macros::{GamePacket, McBuf};
#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundMoveEntityPosPacket {
#[var]
pub entity_id: i32,
- pub xa: i16,
- pub ya: i16,
- pub za: i16,
+ pub delta: PositionDelta,
pub on_ground: bool,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs b/azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs
index 5fde1b93..b02a2981 100644
--- a/azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs
@@ -1,12 +1,12 @@
+use super::clientbound_move_entity_pos_packet::PositionDelta;
use packet_macros::{GamePacket, McBuf};
+/// This packet is sent by the server when an entity moves less then 8 blocks.
#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundMoveEntityPosRotPacket {
#[var]
- pub entity_id: i32,
- pub xa: i16,
- pub ya: i16,
- pub za: i16,
+ pub entity_id: u32,
+ pub delta: PositionDelta,
pub y_rot: i8,
pub x_rot: i8,
pub on_ground: bool,
diff --git a/azalea-world/src/lib.rs b/azalea-world/src/lib.rs
index 10beb309..6e922bb9 100644
--- a/azalea-world/src/lib.rs
+++ b/azalea-world/src/lib.rs
@@ -72,6 +72,22 @@ impl World {
Ok(())
}
+ pub fn move_entity_with_delta(&mut self, entity_id: u32, delta: PositionDelta) -> Result<(), String> {
+ let entity = self
+ .entity_storage
+ .get_mut_by_id(entity_id)
+ .ok_or_else(|| "Moving entity that doesn't exist".to_string())?;
+ let old_chunk = ChunkPos::from(entity.pos());
+ let new_chunk = ChunkPos::from(&new_pos);
+ // this is fine because we update the chunk below
+ entity.unsafe_move(new_pos);
+ if old_chunk != new_chunk {
+ self.entity_storage
+ .update_entity_chunk(entity_id, &old_chunk, &new_chunk);
+ }
+ Ok(())
+ }
+
pub fn add_entity(&mut self, entity: Entity) {
self.entity_storage.insert(entity);
}
diff --git a/bot/src/main.rs b/bot/src/main.rs
index 546a9244..1cb209e5 100644
--- a/bot/src/main.rs
+++ b/bot/src/main.rs
@@ -6,7 +6,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Hello, world!");
// let address = "95.111.249.143:10000";
- let address = "localhost:57172";
+ let address = "localhost:52722";
// let response = azalea_client::ping::ping_server(&address.try_into().unwrap())
// .await
// .unwrap();