diff --git a/.gitignore b/.gitignore
old mode 100755
new mode 100644
index 0c2b742a..53141060
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ flamegraph.svg
perf.data
perf.data.old
+
code-generator/Burger
code-generator/client.jar
code-generator/burger.json
diff --git a/Cargo.lock b/Cargo.lock
index 5674b2e9..0faed271 100755
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -100,6 +100,7 @@ dependencies = [
"azalea-core",
"azalea-crypto",
"azalea-protocol",
+ "azalea-world",
"tokio",
]
@@ -171,6 +172,15 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "azalea-world"
+version = "0.1.0"
+dependencies = [
+ "azalea-core",
+ "azalea-nbt",
+ "azalea-protocol",
+]
+
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -191,6 +201,7 @@ name = "bot"
version = "0.1.0"
dependencies = [
"azalea-client",
+ "azalea-core",
"azalea-protocol",
"tokio",
]
diff --git a/Cargo.toml b/Cargo.toml
old mode 100755
new mode 100644
index 20c66a30..6c1fcaab
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,7 @@ members = [
"azalea-nbt",
"azalea-brigadier",
"azalea-crypto",
+ "azalea-world",
"azalea-language",
]
diff --git a/README.md b/README.md
old mode 100755
new mode 100644
index 084b981d..e214fb09
--- a/README.md
+++ b/README.md
@@ -1,13 +1,17 @@
# Azalea
-A Rust crate for creating Minecraft bots.
-
+A Rust crate for creating Minecraft bots.
+
I named this Azalea because it sounds like a cool word and this is a cool library. This project was heavily inspired by PrismarineJS.
+## Why
+
+I wanted a fun excuse to do something cool with Rust, and I also felt like I could do better than [Mineflayer](https://github.com/prismarinejs/mineflayer) in some areas.
+
## Goals
- Do everything a vanilla client can do.
diff --git a/azalea-client/Cargo.toml b/azalea-client/Cargo.toml
index 55caadeb..1156f8de 100755
--- a/azalea-client/Cargo.toml
+++ b/azalea-client/Cargo.toml
@@ -10,4 +10,5 @@ azalea-auth = {path = "../azalea-auth"}
azalea-core = {path = "../azalea-core"}
azalea-crypto = {path = "../azalea-crypto"}
azalea-protocol = {path = "../azalea-protocol"}
+azalea-world = {path = "../azalea-world"}
tokio = {version = "1.18.0", features = ["sync"]}
diff --git a/azalea-client/src/connect.rs b/azalea-client/src/connect.rs
index 6e6398fa..b8b6e372 100755
--- a/azalea-client/src/connect.rs
+++ b/azalea-client/src/connect.rs
@@ -1,5 +1,5 @@
use crate::Player;
-use azalea_core::resource_location::ResourceLocation;
+use azalea_core::{resource_location::ResourceLocation, ChunkPos};
use azalea_protocol::{
connect::{GameConnection, HandshakeConnection},
packets::{
@@ -17,7 +17,8 @@ use azalea_protocol::{
},
resolver, ServerAddress,
};
-use std::sync::Arc;
+use azalea_world::{ChunkStorage, World};
+use std::{fmt::Debug, sync::Arc};
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
use tokio::sync::Mutex;
@@ -30,15 +31,15 @@ pub struct Account {
#[derive(Default)]
pub struct ClientState {
- // placeholder
pub player: Player,
+ pub world: Option,
}
/// A player that you can control that is currently in a Minecraft server.
pub struct Client {
event_receiver: UnboundedReceiver,
- conn: Arc>,
- state: Arc>,
+ pub conn: Arc>,
+ pub state: Arc>,
// game_loop
}
@@ -137,10 +138,9 @@ impl Client {
// just start up the game loop and we're ready!
// tokio::spawn(Self::game_loop(conn, tx, handler, state))
- let game_loop_conn = conn.clone();
let game_loop_state = client.state.clone();
- tokio::spawn(Self::game_loop(game_loop_conn, tx, game_loop_state));
+ tokio::spawn(Self::game_loop(conn, tx, game_loop_state));
Ok(client)
}
@@ -178,7 +178,37 @@ impl Client {
GamePacket::ClientboundLoginPacket(p) => {
println!("Got login packet {:?}", p);
- state.lock().await.player.entity.id = p.player_id;
+ let mut state = state.lock().await;
+ state.player.entity.id = p.player_id;
+ let dimension_type = p
+ .dimension_type
+ .as_compound()
+ .expect("Dimension type is not compound")
+ .get("")
+ .expect("No \"\" tag")
+ .as_compound()
+ .expect("\"\" tag is not compound");
+ let height = (*dimension_type
+ .get("height")
+ .expect("No height tag")
+ .as_int()
+ .expect("height tag is not int"))
+ .try_into()
+ .expect("height is not a u32");
+ let min_y = (*dimension_type
+ .get("min_y")
+ .expect("No min_y tag")
+ .as_int()
+ .expect("min_y tag is not int"))
+ .try_into()
+ .expect("min_y is not an i32");
+
+ state.world = Some(World {
+ height,
+ min_y,
+ storage: ChunkStorage::new(16),
+ });
+
conn.lock()
.await
.write(
@@ -202,7 +232,7 @@ impl Client {
GamePacket::ClientboundChangeDifficultyPacket(p) => {
println!("Got difficulty packet {:?}", p);
}
- GamePacket::ClientboundDeclareCommandsPacket(p) => {
+ GamePacket::ClientboundDeclareCommandsPacket(_p) => {
println!("Got declare commands packet");
}
GamePacket::ClientboundPlayerAbilitiesPacket(p) => {
@@ -211,19 +241,19 @@ impl Client {
GamePacket::ClientboundSetCarriedItemPacket(p) => {
println!("Got set carried item packet {:?}", p);
}
- GamePacket::ClientboundUpdateTagsPacket(p) => {
+ GamePacket::ClientboundUpdateTagsPacket(_p) => {
println!("Got update tags packet");
}
GamePacket::ClientboundDisconnectPacket(p) => {
println!("Got disconnect packet {:?}", p);
}
- GamePacket::ClientboundUpdateRecipesPacket(p) => {
+ GamePacket::ClientboundUpdateRecipesPacket(_p) => {
println!("Got update recipes packet");
}
GamePacket::ClientboundEntityEventPacket(p) => {
// println!("Got entity event packet {:?}", p);
}
- GamePacket::ClientboundRecipePacket(p) => {
+ GamePacket::ClientboundRecipePacket(_p) => {
println!("Got recipe packet");
}
GamePacket::ClientboundPlayerPositionPacket(p) => {
@@ -235,9 +265,27 @@ impl Client {
}
GamePacket::ClientboundSetChunkCacheCenterPacket(p) => {
println!("Got chunk cache center packet {:?}", p);
+ state
+ .lock()
+ .await
+ .world
+ .as_mut()
+ .unwrap()
+ .update_view_center(&ChunkPos::new(p.x, p.z));
}
GamePacket::ClientboundLevelChunkWithLightPacket(p) => {
println!("Got chunk with light packet {} {}", p.x, p.z);
+ let pos = ChunkPos::new(p.x, p.z);
+ // let chunk = Chunk::read_with_world_height(&mut p.chunk_data);
+ // println("chunk {:?}")
+ state
+ .lock()
+ .await
+ .world
+ .as_mut()
+ .expect("World doesn't exist! We should've gotten a login packet by now.")
+ .replace_with_packet_data(&pos, &mut p.chunk_data.data.as_slice())
+ .unwrap();
}
GamePacket::ClientboundLightUpdatePacket(p) => {
println!("Got light update packet {:?}", p);
@@ -321,10 +369,21 @@ impl Client {
}
GamePacket::ClientboundBlockUpdatePacket(p) => {
println!("Got block update packet {:?}", p);
+ // TODO: update world
}
GamePacket::ClientboundAnimatePacket(p) => {
println!("Got animate packet {:?}", p);
}
+ GamePacket::ClientboundSectionBlocksUpdatePacket(p) => {
+ println!("Got section blocks update packet {:?}", p);
+ // TODO: update world
+ }
+ GamePacket::ClientboundGameEventPacket(p) => {
+ println!("Got game event packet {:?}", p);
+ }
+ GamePacket::ClientboundLevelParticlesPacket(p) => {
+ println!("Got level particles packet {:?}", p);
+ }
_ => panic!("Unexpected packet {:?}", packet),
}
}
diff --git a/azalea-core/src/block_pos.rs b/azalea-core/src/block_pos.rs
deleted file mode 100644
index 96a234cb..00000000
--- a/azalea-core/src/block_pos.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#[derive(Clone, Copy, Debug)]
-pub struct BlockPos {
- pub x: i32,
- pub y: i32,
- pub z: i32,
-}
diff --git a/azalea-core/src/difficulty.rs b/azalea-core/src/difficulty.rs
index 21e980ba..5d869325 100755
--- a/azalea-core/src/difficulty.rs
+++ b/azalea-core/src/difficulty.rs
@@ -83,7 +83,6 @@ mod tests {
assert_eq!(1, Difficulty::EASY.id());
assert_eq!(2, Difficulty::NORMAL.id());
assert_eq!(3, Difficulty::HARD.id());
- assert_eq!(4, Difficulty::PEACEFUL.id());
}
#[test]
diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs
index c6b51cb1..d2a2d558 100755
--- a/azalea-core/src/lib.rs
+++ b/azalea-core/src/lib.rs
@@ -1,5 +1,7 @@
//! Random miscellaneous things like UUIDs that don't deserve their own crate.
+#![feature(int_roundings)]
+
pub mod difficulty;
pub mod game_type;
pub mod resource_location;
@@ -8,8 +10,8 @@ pub mod serializable_uuid;
mod slot;
pub use slot::{Slot, SlotData};
-mod block_pos;
-pub use block_pos::BlockPos;
+mod position;
+pub use position::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos, ChunkSectionPos};
mod direction;
pub use direction::Direction;
diff --git a/azalea-core/src/position.rs b/azalea-core/src/position.rs
new file mode 100644
index 00000000..9c7cd132
--- /dev/null
+++ b/azalea-core/src/position.rs
@@ -0,0 +1,157 @@
+use std::ops::Rem;
+
+#[derive(Clone, Copy, Debug, Default)]
+pub struct BlockPos {
+ pub x: i32,
+ pub y: i32,
+ pub z: i32,
+}
+
+impl BlockPos {
+ pub fn new(x: i32, y: i32, z: i32) -> Self {
+ BlockPos { x, y, z }
+ }
+}
+
+impl Rem for BlockPos {
+ type Output = Self;
+
+ fn rem(self, rhs: i32) -> Self {
+ BlockPos {
+ x: self.x % rhs,
+ y: self.y % rhs,
+ z: self.z % rhs,
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, Default, PartialEq)]
+pub struct ChunkPos {
+ pub x: i32,
+ pub z: i32,
+}
+
+impl ChunkPos {
+ pub fn new(x: i32, z: i32) -> Self {
+ ChunkPos { x, z }
+ }
+}
+
+impl From<&BlockPos> for ChunkPos {
+ fn from(pos: &BlockPos) -> Self {
+ ChunkPos {
+ x: pos.x.div_floor(16),
+ z: pos.z.div_floor(16),
+ }
+ }
+}
+
+/// The coordinates of a chunk section in the world.
+#[derive(Clone, Copy, Debug, Default)]
+pub struct ChunkSectionPos {
+ pub x: i32,
+ pub y: i32,
+ pub z: i32,
+}
+
+impl ChunkSectionPos {
+ pub fn new(x: i32, y: i32, z: i32) -> Self {
+ ChunkSectionPos { x, y, z }
+ }
+}
+
+impl From for ChunkSectionPos {
+ fn from(pos: BlockPos) -> Self {
+ ChunkSectionPos {
+ x: pos.x.div_floor(16),
+ y: pos.y.div_floor(16),
+ z: pos.z.div_floor(16),
+ }
+ }
+}
+
+impl From for ChunkPos {
+ fn from(pos: ChunkSectionPos) -> Self {
+ ChunkPos { x: pos.x, z: pos.z }
+ }
+}
+
+/// The coordinates of a block inside a chunk.
+#[derive(Clone, Copy, Debug, Default, PartialEq)]
+pub struct ChunkBlockPos {
+ pub x: u8,
+ pub y: i32,
+ pub z: u8,
+}
+
+impl ChunkBlockPos {
+ pub fn new(x: u8, y: i32, z: u8) -> Self {
+ ChunkBlockPos { x, y, z }
+ }
+}
+
+impl From<&BlockPos> for ChunkBlockPos {
+ fn from(pos: &BlockPos) -> Self {
+ ChunkBlockPos {
+ x: pos.x.rem_euclid(16).abs() as u8,
+ y: pos.y,
+ z: pos.z.rem_euclid(16).abs() as u8,
+ }
+ }
+}
+
+/// The coordinates of a block inside a chunk section.
+#[derive(Clone, Copy, Debug, Default)]
+pub struct ChunkSectionBlockPos {
+ /// A number between 0 and 16.
+ pub x: u8,
+ /// A number between 0 and 16.
+ pub y: u8,
+ /// A number between 0 and 16.
+ pub z: u8,
+}
+
+impl ChunkSectionBlockPos {
+ pub fn new(x: u8, y: u8, z: u8) -> Self {
+ ChunkSectionBlockPos { x, y, z }
+ }
+}
+
+impl From<&BlockPos> for ChunkSectionBlockPos {
+ fn from(pos: &BlockPos) -> Self {
+ ChunkSectionBlockPos {
+ x: pos.x.rem(16).abs() as u8,
+ y: pos.y.rem(16).abs() as u8,
+ z: pos.z.rem(16).abs() as u8,
+ }
+ }
+}
+
+impl From<&ChunkBlockPos> for ChunkSectionBlockPos {
+ fn from(pos: &ChunkBlockPos) -> Self {
+ ChunkSectionBlockPos {
+ x: pos.x,
+ y: pos.y.rem(16).abs() as u8,
+ z: pos.z,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_from_block_pos_to_chunk_pos() {
+ let block_pos = BlockPos::new(5, 78, -2);
+ let chunk_pos = ChunkPos::from(&block_pos);
+ assert_eq!(chunk_pos, ChunkPos::new(0, -1));
+ }
+
+ #[test]
+ fn test_from_block_pos_to_chunk_block_pos() {
+ let block_pos = BlockPos::new(5, 78, -2);
+ let chunk_block_pos = ChunkBlockPos::from(&block_pos);
+ assert_eq!(chunk_block_pos, ChunkBlockPos::new(5, 78, 14));
+ }
+}
diff --git a/azalea-crypto/src/lib.rs b/azalea-crypto/src/lib.rs
index f47b91fe..c233b231 100644
--- a/azalea-crypto/src/lib.rs
+++ b/azalea-crypto/src/lib.rs
@@ -1,9 +1,6 @@
use aes::cipher::inout::InOutBuf;
-use aes::cipher::BlockEncrypt;
use aes::{
- cipher::{
- generic_array::GenericArray, AsyncStreamCipher, BlockDecryptMut, BlockEncryptMut, KeyIvInit,
- },
+ cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit},
Aes128,
};
use rand::{rngs::OsRng, RngCore};
@@ -15,7 +12,7 @@ fn generate_secret_key() -> [u8; 16] {
key
}
-fn digest_data(server_id: &[u8], public_key: &[u8], private_key: &[u8]) -> Vec {
+pub fn digest_data(server_id: &[u8], public_key: &[u8], private_key: &[u8]) -> Vec {
let mut digest = Sha1::new();
digest.update(server_id);
digest.update(public_key);
@@ -23,7 +20,7 @@ fn digest_data(server_id: &[u8], public_key: &[u8], private_key: &[u8]) -> Vec String {
+pub fn hex_digest(digest: &[u8]) -> String {
// Note that the Sha1.hexdigest() method used by minecraft is non standard.
// It doesn't match the digest method found in most programming languages
// and libraries. It works by treating the sha1 output bytes as one large
@@ -48,9 +45,8 @@ pub fn encrypt(public_key: &[u8], nonce: &[u8]) -> Result
// this.keybytes = Crypt.encryptUsingKey(publicKey, secretKey.getEncoded());
// this.nonce = Crypt.encryptUsingKey(publicKey, arrby);
- let encrypted_public_key: Vec =
- rsa_public_encrypt_pkcs1::encrypt(&public_key, &secret_key)?;
- let encrypted_nonce: Vec = rsa_public_encrypt_pkcs1::encrypt(&public_key, &nonce)?;
+ let encrypted_public_key: Vec = rsa_public_encrypt_pkcs1::encrypt(public_key, &secret_key)?;
+ let encrypted_nonce: Vec = rsa_public_encrypt_pkcs1::encrypt(public_key, nonce)?;
Ok(EncryptResult {
secret_key,
diff --git a/azalea-language/src/lib.rs b/azalea-language/src/lib.rs
index 3647d4c7..f54de3cb 100644
--- a/azalea-language/src/lib.rs
+++ b/azalea-language/src/lib.rs
@@ -1,6 +1,7 @@
use lazy_static::lazy_static;
-use std::collections::HashMap;
-
+use std::io::Read;
+use std::path::Path;
+use std::{collections::HashMap, fs::File};
// use tokio::fs::File;
// pub struct Language {
@@ -29,10 +30,26 @@ use std::collections::HashMap;
// The code above is kept in case I come up with a better solution
lazy_static! {
- pub static ref STORAGE: HashMap =
- serde_json::from_str(include_str!("en_us.json")).unwrap();
+ pub static ref STORAGE: HashMap = serde_json::from_str(&{
+ let src_dir = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/src/en_us.json"));
+ let mut file = File::open(src_dir).unwrap();
+ let mut contents = String::new();
+ file.read_to_string(&mut contents).unwrap();
+ contents
+ })
+ .unwrap();
}
pub fn get(key: &str) -> Option<&str> {
STORAGE.get(key).map(|s| s.as_str())
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_get() {
+ assert_eq!(get("translation.test.none"), Some("Hello, world!"));
+ }
+}
diff --git a/azalea-nbt/src/encode.rs b/azalea-nbt/src/encode.rs
index 20d13793..fb5585b3 100755
--- a/azalea-nbt/src/encode.rs
+++ b/azalea-nbt/src/encode.rs
@@ -98,7 +98,7 @@ fn write_compound(
if end_tag {
writer.write_u8(Tag::End.id())?;
}
- return Ok(());
+ Ok(())
}
#[inline]
diff --git a/azalea-nbt/src/tag.rs b/azalea-nbt/src/tag.rs
index 61bd15ba..e2df08f7 100755
--- a/azalea-nbt/src/tag.rs
+++ b/azalea-nbt/src/tag.rs
@@ -17,6 +17,12 @@ pub enum Tag {
LongArray(Vec), // 12
}
+impl Default for Tag {
+ fn default() -> Self {
+ Tag::End
+ }
+}
+
impl Tag {
#[inline]
pub fn id(&self) -> u8 {
diff --git a/azalea-protocol/README.md b/azalea-protocol/README.md
old mode 100755
new mode 100644
index 52aaebd2..b4741a3b
--- a/azalea-protocol/README.md
+++ b/azalea-protocol/README.md
@@ -2,11 +2,11 @@
Sent and receive Minecraft packets. You should probably use `azalea` or `azalea-client` instead.
-The goal is to **only** support the latest Minecraft version in order to ease development.
+The goal is to only support the latest Minecraft version in order to ease development.
This is not yet complete, search for `TODO` in the code for things that need to be done.
-Unfortunately, compiling the crate requires Rust nightly because specialization is not stable yet.
+Unfortunately, using azalea-protocol requires Rust nightly because [specialization](https://github.com/rust-lang/rust/issues/31844) is not stable yet. Use `rustup default nightly` to enable it.
## Adding a new packet
diff --git a/azalea-protocol/packet-macros/src/lib.rs b/azalea-protocol/packet-macros/src/lib.rs
index 35bf8b9b..f3fe4e40 100755
--- a/azalea-protocol/packet-macros/src/lib.rs
+++ b/azalea-protocol/packet-macros/src/lib.rs
@@ -157,6 +157,19 @@ pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream {
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);
@@ -169,8 +182,8 @@ 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 _mcbufreadable_impl = create_impl_mcbufreadable(&ident, &data);
+ let _mcbufwritable_impl = create_impl_mcbufwritable(&ident, &data);
let contents = quote! {
impl #ident {
@@ -189,10 +202,6 @@ fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> Toke
Ok(Self::read_into(buf)?.get())
}
}
-
- #mcbufreadable_impl
-
- #mcbufwritable_impl
};
contents.into()
@@ -232,13 +241,12 @@ struct PacketIdMap {
impl Parse for PacketIdMap {
fn parse(input: ParseStream) -> Result {
let mut packets = vec![];
- loop {
- // 0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket,
- // 0x0e
- let packet_id: LitInt = match input.parse() {
- Ok(i) => i,
- Err(_) => break,
- };
+
+ // example:
+ // 0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket,
+
+ // 0x0e
+ while let Ok(packet_id) = input.parse::() {
let packet_id = packet_id.base10_parse::()?;
// :
input.parse::()?;
diff --git a/azalea-protocol/src/mc_buf/definitions.rs b/azalea-protocol/src/mc_buf/definitions.rs
index a59fc574..3867b3fc 100644
--- a/azalea-protocol/src/mc_buf/definitions.rs
+++ b/azalea-protocol/src/mc_buf/definitions.rs
@@ -1,8 +1,9 @@
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::{McBufReadable, McBufWritable};
+use packet_macros::McBuf;
use std::io::{Read, Write};
use std::ops::Deref;
use uuid::Uuid;
@@ -32,7 +33,7 @@ impl From<&str> for UnsizedByteArray {
}
/// Represents Java's BitSet, a list of bits.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, McBufReadable, McBufWritable)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash, McBuf)]
pub struct BitSet {
data: Vec,
}
@@ -159,7 +160,7 @@ impl McBufWritable for EntityDataValue {
}
}
-#[derive(Clone, Debug, Copy, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, Copy, McBuf)]
pub enum Pose {
Standing = 0,
FallFlying = 1,
@@ -171,7 +172,7 @@ pub enum Pose {
Dying = 7,
}
-#[derive(Debug, Clone, McBufReadable, McBufWritable)]
+#[derive(Debug, Clone, McBuf)]
pub struct VillagerData {
#[var]
type_: u32,
@@ -181,7 +182,7 @@ pub struct VillagerData {
level: u32,
}
-#[derive(Debug, Clone, McBufReadable, McBufWritable)]
+#[derive(Debug, Clone, McBuf)]
pub struct Particle {
#[var]
pub id: i32,
@@ -280,12 +281,12 @@ pub enum ParticleData {
Scrape,
}
-#[derive(Debug, Clone, McBufReadable, McBufWritable)]
+#[derive(Debug, Clone, McBuf)]
pub struct BlockParticle {
#[var]
pub block_state: i32,
}
-#[derive(Debug, Clone, McBufReadable, McBufWritable)]
+#[derive(Debug, Clone, McBuf)]
pub struct DustParticle {
/// Red value, 0-1
pub red: f32,
@@ -297,7 +298,7 @@ pub struct DustParticle {
pub scale: f32,
}
-#[derive(Debug, Clone, McBufReadable, McBufWritable)]
+#[derive(Debug, Clone, McBuf)]
pub struct DustColorTransitionParticle {
/// Red value, 0-1
pub from_red: f32,
@@ -315,12 +316,12 @@ pub struct DustColorTransitionParticle {
pub to_blue: f32,
}
-#[derive(Debug, Clone, McBufReadable, McBufWritable)]
+#[derive(Debug, Clone, McBuf)]
pub struct ItemParticle {
pub item: Slot,
}
-#[derive(Debug, Clone, McBufReadable, McBufWritable)]
+#[derive(Debug, Clone, McBuf)]
pub struct VibrationParticle {
pub origin: BlockPos,
pub position_type: String,
@@ -331,9 +332,8 @@ pub struct VibrationParticle {
pub ticks: u32,
}
-impl McBufReadable for ParticleData {
- fn read_into(buf: &mut impl Read) -> Result {
- let id = buf.read_varint()?;
+impl ParticleData {
+ pub fn read_from_particle_id(buf: &mut impl Read, id: u32) -> Result {
Ok(match id {
0 => ParticleData::AmbientEntityEffect,
1 => ParticleData::AngryVillager,
@@ -428,6 +428,13 @@ impl McBufReadable for ParticleData {
}
}
+impl McBufReadable for ParticleData {
+ fn read_into(buf: &mut impl Read) -> Result {
+ let id = u32::var_read_into(buf)?;
+ ParticleData::read_from_particle_id(buf, id)
+ }
+}
+
impl McBufWritable for ParticleData {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
todo!()
diff --git a/azalea-protocol/src/mc_buf/mod.rs b/azalea-protocol/src/mc_buf/mod.rs
old mode 100755
new mode 100644
index bee269c9..548ba7c2
--- a/azalea-protocol/src/mc_buf/mod.rs
+++ b/azalea-protocol/src/mc_buf/mod.rs
@@ -4,16 +4,16 @@ mod definitions;
mod read;
mod write;
-pub use definitions::{BitSet, EntityMetadata, UnsizedByteArray};
-use packet_macros::{McBufReadable, McBufWritable};
+pub use definitions::{BitSet, EntityMetadata, ParticleData, UnsizedByteArray};
pub use read::{read_varint_async, McBufReadable, McBufVarReadable, Readable};
-use std::ops::Deref;
pub use write::{McBufVarWritable, McBufWritable, Writable};
// const DEFAULT_NBT_QUOTA: u32 = 2097152;
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)]
diff --git a/azalea-protocol/src/mc_buf/read.rs b/azalea-protocol/src/mc_buf/read.rs
old mode 100755
new mode 100644
index 98a3ee53..1c4fbd6f
--- a/azalea-protocol/src/mc_buf/read.rs
+++ b/azalea-protocol/src/mc_buf/read.rs
@@ -1,10 +1,10 @@
-use super::{BitSet, UnsizedByteArray, MAX_STRING_LENGTH};
+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, Direction, Slot, SlotData,
+ serializable_uuid::SerializableUuid, BlockPos, ChunkSectionPos, Direction, Slot, SlotData,
};
-use byteorder::{ReadBytesExt, WriteBytesExt, BE};
+use byteorder::{ReadBytesExt, BE};
use serde::Deserialize;
use std::{collections::HashMap, hash::Hash, io::Read};
use tokio::io::{AsyncRead, AsyncReadExt};
@@ -466,7 +466,7 @@ impl McBufReadable for Component {
fn read_into(buf: &mut impl Read) -> Result {
let string = buf.read_utf()?;
let json: serde_json::Value = serde_json::from_str(string.as_str())
- .map_err(|e| "Component isn't valid JSON".to_string())?;
+ .map_err(|_| "Component isn't valid JSON".to_string())?;
let component = Component::deserialize(json).map_err(|e| e.to_string())?;
Ok(component)
}
@@ -518,3 +518,15 @@ impl McBufReadable for Direction {
}
}
}
+
+// ChunkSectionPos
+impl McBufReadable for ChunkSectionPos {
+ fn read_into(buf: &mut impl Read) -> Result {
+ 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,
+ })
+ }
+}
diff --git a/azalea-protocol/src/mc_buf/write.rs b/azalea-protocol/src/mc_buf/write.rs
old mode 100755
new mode 100644
index e3e7a2be..c46297a6
--- a/azalea-protocol/src/mc_buf/write.rs
+++ b/azalea-protocol/src/mc_buf/write.rs
@@ -2,7 +2,7 @@ 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, Direction, Slot,
+ serializable_uuid::SerializableUuid, BlockPos, ChunkSectionPos, Direction, Slot,
};
use byteorder::{BigEndian, WriteBytesExt};
use std::{collections::HashMap, io::Write};
@@ -20,8 +20,8 @@ pub trait Writable: Write {
Ok(())
}
- fn write_int_id_list(&mut self, list: &Vec) -> Result<(), std::io::Error> {
- self.write_list(&list, |buf, n| buf.write_varint(*n))
+ fn write_int_id_list(&mut self, list: &[i32]) -> Result<(), std::io::Error> {
+ self.write_list(list, |buf, n| buf.write_varint(*n))
}
fn write_map(
@@ -47,7 +47,7 @@ pub trait Writable: Write {
}
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), std::io::Error> {
- self.write_all(bytes);
+ self.write_all(bytes)?;
Ok(())
}
@@ -377,7 +377,7 @@ impl McBufWritable for Component {
// 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> {
+ fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
// component doesn't have serialize implemented yet
todo!()
}
@@ -425,3 +425,14 @@ impl McBufWritable for Direction {
buf.write_varint(*self as i32)
}
}
+
+// ChunkSectionPos
+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(())
+ }
+}
diff --git a/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs b/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs
index 55fbd2e1..9afd151b 100644
--- a/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs
@@ -1,7 +1,7 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
use uuid::Uuid;
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundAddEntityPacket {
#[var]
pub id: i32,
diff --git a/azalea-protocol/src/packets/game/clientbound_add_mob_packet.rs b/azalea-protocol/src/packets/game/clientbound_add_mob_packet.rs
index ab72eb59..bc0ddcef 100644
--- a/azalea-protocol/src/packets/game/clientbound_add_mob_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_add_mob_packet.rs
@@ -1,7 +1,7 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
use uuid::Uuid;
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundAddMobPacket {
#[var]
pub id: i32,
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 8f848c99..f1947d09 100644
--- a/azalea-protocol/src/packets/game/clientbound_add_player_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_add_player_packet.rs
@@ -1,7 +1,7 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
use uuid::Uuid;
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundAddPlayerPacket {
#[var]
pub id: i32,
diff --git a/azalea-protocol/src/packets/game/clientbound_animate_packet.rs b/azalea-protocol/src/packets/game/clientbound_animate_packet.rs
index 84a20381..0bba1a25 100644
--- a/azalea-protocol/src/packets/game/clientbound_animate_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_animate_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundAnimatePacket {
#[var]
pub id: u32,
@@ -9,7 +9,7 @@ pub struct ClientboundAnimatePacket {
// minecraft actually uses a u8 for this, but a varint still works and makes it
// so i don't have to add a special handler
-#[derive(Clone, Debug, Copy, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, Copy, McBuf)]
pub enum AnimationAction {
SwingMainHand = 0,
Hurt = 1,
diff --git a/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs
index 575b7f46..f068cc7d 100644
--- a/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs
@@ -1,7 +1,7 @@
use azalea_core::BlockPos;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundBlockUpdatePacket {
pub pos: BlockPos,
// TODO: in vanilla this is a BlockState, but here we just have it as a number.
diff --git a/azalea-protocol/src/packets/game/clientbound_change_difficulty_packet.rs b/azalea-protocol/src/packets/game/clientbound_change_difficulty_packet.rs
index e12cfff3..edda52d9 100755
--- a/azalea-protocol/src/packets/game/clientbound_change_difficulty_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_change_difficulty_packet.rs
@@ -1,7 +1,7 @@
use azalea_core::difficulty::Difficulty;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundChangeDifficultyPacket {
pub difficulty: Difficulty,
pub locked: bool,
diff --git a/azalea-protocol/src/packets/game/clientbound_chat_packet.rs b/azalea-protocol/src/packets/game/clientbound_chat_packet.rs
index 3786993a..77c5370c 100644
--- a/azalea-protocol/src/packets/game/clientbound_chat_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_chat_packet.rs
@@ -1,15 +1,15 @@
use azalea_chat::component::Component;
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use packet_macros::{GamePacket, McBuf};
use uuid::Uuid;
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundChatPacket {
pub message: Component,
pub type_: ChatType,
pub sender: Uuid,
}
-#[derive(Clone, Debug, Copy, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, Copy, McBuf)]
pub enum ChatType {
Chat = 0,
System = 1,
diff --git a/azalea-protocol/src/packets/game/clientbound_container_set_content_packet.rs b/azalea-protocol/src/packets/game/clientbound_container_set_content_packet.rs
index aea09e09..d38bbfda 100644
--- a/azalea-protocol/src/packets/game/clientbound_container_set_content_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_container_set_content_packet.rs
@@ -1,7 +1,7 @@
use azalea_core::Slot;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundContainerSetContentPacket {
pub container_id: u8,
#[var]
diff --git a/azalea-protocol/src/packets/game/clientbound_custom_payload_packet.rs b/azalea-protocol/src/packets/game/clientbound_custom_payload_packet.rs
index 2c56ea2b..b9ccbba4 100755
--- a/azalea-protocol/src/packets/game/clientbound_custom_payload_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_custom_payload_packet.rs
@@ -1,8 +1,8 @@
use crate::mc_buf::UnsizedByteArray;
use azalea_core::resource_location::ResourceLocation;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundCustomPayloadPacket {
pub identifier: ResourceLocation,
pub data: UnsizedByteArray,
diff --git a/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs b/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs
index 27f4fb16..6743c3af 100755
--- a/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_declare_commands_packet.rs
@@ -281,7 +281,7 @@ impl McBufReadable for BrigadierParser {
}
}
-// azalea_brigadier::tree::CommandNode
+// TODO: BrigadierNodeStub should have more stuff
impl McBufReadable for BrigadierNodeStub {
fn read_into(buf: &mut impl Read) -> Result {
let flags = u8::read_into(buf)?;
@@ -292,20 +292,18 @@ impl McBufReadable for BrigadierNodeStub {
}
let node_type = flags & 0x03;
- let is_executable = flags & 0x04 != 0;
+ let _is_executable = flags & 0x04 != 0;
let has_redirect = flags & 0x08 != 0;
let has_suggestions_type = flags & 0x10 != 0;
- let children = buf.read_int_id_list()?;
- let redirect_node = if has_redirect { buf.read_varint()? } else { 0 };
+ let _children = buf.read_int_id_list()?;
+ let _redirect_node = if has_redirect { buf.read_varint()? } else { 0 };
// argument node
if node_type == 2 {
- let name = buf.read_utf()?;
-
- let parser = BrigadierParser::read_into(buf)?;
-
- let suggestions_type = if has_suggestions_type {
+ let _name = buf.read_utf()?;
+ let _parser = BrigadierParser::read_into(buf)?;
+ let _suggestions_type = if has_suggestions_type {
Some(buf.read_resource_location()?)
} else {
None
@@ -314,7 +312,7 @@ impl McBufReadable for BrigadierNodeStub {
}
// literal node
if node_type == 1 {
- let name = buf.read_utf()?;
+ let _name = buf.read_utf()?;
return Ok(BrigadierNodeStub {});
}
Ok(BrigadierNodeStub {})
diff --git a/azalea-protocol/src/packets/game/clientbound_disconnect_packet.rs b/azalea-protocol/src/packets/game/clientbound_disconnect_packet.rs
index 2e72b19b..c030d512 100644
--- a/azalea-protocol/src/packets/game/clientbound_disconnect_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_disconnect_packet.rs
@@ -1,7 +1,7 @@
use azalea_chat::component::Component;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundDisconnectPacket {
pub reason: Component,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs b/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs
index 55e4d419..1b06bff7 100644
--- a/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_entity_event_packet.rs
@@ -1,7 +1,7 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
// we can't identify the status in azalea-protocol since they vary depending on the entity
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundEntityEventPacket {
pub entity_id: i32,
pub entity_status: i8,
diff --git a/azalea-protocol/src/packets/game/clientbound_entity_velocity_packet.rs b/azalea-protocol/src/packets/game/clientbound_entity_velocity_packet.rs
index 4fc8f86f..07218c4e 100644
--- a/azalea-protocol/src/packets/game/clientbound_entity_velocity_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_entity_velocity_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundEntityVelocityPacket {
#[var]
pub entity_id: u32,
diff --git a/azalea-protocol/src/packets/game/clientbound_game_event_packet.rs b/azalea-protocol/src/packets/game/clientbound_game_event_packet.rs
new file mode 100644
index 00000000..dd5f08f6
--- /dev/null
+++ b/azalea-protocol/src/packets/game/clientbound_game_event_packet.rs
@@ -0,0 +1,23 @@
+use packet_macros::{GamePacket, McBuf};
+
+#[derive(Clone, Debug, McBuf, GamePacket)]
+pub struct ClientboundGameEventPacket {
+ pub event: EventType,
+ pub param: f32,
+}
+
+#[derive(Clone, Debug, Copy, McBuf)]
+pub enum EventType {
+ NoRespawnBlockAvailable = 0,
+ StartRaining = 1,
+ StopRaining = 2,
+ ChangeGameMode = 3,
+ WinGame = 4,
+ DemoEvent = 5,
+ ArrowHitPlayer = 6,
+ RainLevelChange = 7,
+ ThunderLevelChange = 8,
+ PufferFishSting = 9,
+ GuardianElderEffect = 10,
+ ImmediateRespawn = 11,
+}
diff --git a/azalea-protocol/src/packets/game/clientbound_initialize_border_packet.rs b/azalea-protocol/src/packets/game/clientbound_initialize_border_packet.rs
index 435e43cc..a522eba3 100644
--- a/azalea-protocol/src/packets/game/clientbound_initialize_border_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_initialize_border_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundInitializeBorderPacket {
pub new_center_x: f64,
pub new_center_z: f64,
diff --git a/azalea-protocol/src/packets/game/clientbound_keep_alive_packet.rs b/azalea-protocol/src/packets/game/clientbound_keep_alive_packet.rs
index d5dab9a9..18628c86 100644
--- a/azalea-protocol/src/packets/game/clientbound_keep_alive_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_keep_alive_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundKeepAlivePacket {
pub id: u64,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs b/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs
index 22eedb05..43bda0b6 100644
--- a/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs
@@ -1,8 +1,8 @@
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use packet_macros::{GamePacket, McBuf};
use super::clientbound_light_update_packet::ClientboundLightUpdatePacketData;
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundLevelChunkWithLightPacket {
pub x: i32,
pub z: i32,
@@ -10,25 +10,19 @@ pub struct ClientboundLevelChunkWithLightPacket {
pub light_data: ClientboundLightUpdatePacketData,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct ClientboundLevelChunkPacketData {
- heightmaps: azalea_nbt::Tag,
+ pub heightmaps: azalea_nbt::Tag,
// we can't parse the data in azalea-protocol because it dependso on context from other packets
- data: Vec,
- block_entities: Vec,
+ pub data: Vec,
+ pub block_entities: Vec,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct BlockEntity {
- packed_xz: u8,
- y: u16,
+ pub packed_xz: u8,
+ pub y: u16,
#[var]
- type_: i32,
- data: azalea_nbt::Tag,
-}
-
-pub struct ChunkSection {}
-
-impl ClientboundLevelChunkPacketData {
- pub fn read(world_height: u32) {}
+ pub type_: i32,
+ pub data: azalea_nbt::Tag,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_level_event_packet.rs b/azalea-protocol/src/packets/game/clientbound_level_event_packet.rs
index b8572a85..70926268 100644
--- a/azalea-protocol/src/packets/game/clientbound_level_event_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_level_event_packet.rs
@@ -1,7 +1,7 @@
use azalea_core::BlockPos;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundLevelEventPacket {
pub type_: i32,
pub pos: BlockPos,
diff --git a/azalea-protocol/src/packets/game/clientbound_level_particles_packet.rs b/azalea-protocol/src/packets/game/clientbound_level_particles_packet.rs
new file mode 100644
index 00000000..a3538598
--- /dev/null
+++ b/azalea-protocol/src/packets/game/clientbound_level_particles_packet.rs
@@ -0,0 +1,56 @@
+use std::io::{Read, Write};
+
+use crate::mc_buf::{McBufReadable, McBufWritable, ParticleData};
+use packet_macros::GamePacket;
+
+#[derive(Clone, Debug, GamePacket)]
+pub struct ClientboundLevelParticlesPacket {
+ pub particle_id: u32,
+ pub override_limiter: bool,
+ pub x: f64,
+ pub y: f64,
+ pub z: f64,
+ pub x_dist: f32,
+ pub y_dist: f32,
+ pub z_dist: f32,
+ pub max_speed: f32,
+ pub count: i32,
+ pub data: ParticleData,
+}
+
+impl McBufReadable for ClientboundLevelParticlesPacket {
+ fn read_into(buf: &mut impl Read) -> Result {
+ let particle_id = u32::read_into(buf)?;
+ let override_limiter = bool::read_into(buf)?;
+ let x = f64::read_into(buf)?;
+ let y = f64::read_into(buf)?;
+ let z = f64::read_into(buf)?;
+ let x_dist = f32::read_into(buf)?;
+ let y_dist = f32::read_into(buf)?;
+ let z_dist = f32::read_into(buf)?;
+ let max_speed = f32::read_into(buf)?;
+ let count = i32::read_into(buf)?;
+
+ let data = ParticleData::read_from_particle_id(buf, particle_id)?;
+
+ Ok(Self {
+ particle_id,
+ override_limiter,
+ x,
+ y,
+ z,
+ x_dist,
+ y_dist,
+ z_dist,
+ max_speed,
+ count,
+ data,
+ })
+ }
+}
+
+impl McBufWritable for ClientboundLevelParticlesPacket {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ todo!();
+ }
+}
diff --git a/azalea-protocol/src/packets/game/clientbound_light_update_packet.rs b/azalea-protocol/src/packets/game/clientbound_light_update_packet.rs
index c97eacff..f04987ac 100644
--- a/azalea-protocol/src/packets/game/clientbound_light_update_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_light_update_packet.rs
@@ -1,15 +1,14 @@
use crate::mc_buf::BitSet;
-use azalea_core::{game_type::GameType, resource_location::ResourceLocation};
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundLightUpdatePacket {
pub x: i32,
pub z: i32,
pub light_data: ClientboundLightUpdatePacketData,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct ClientboundLightUpdatePacketData {
trust_edges: bool,
sky_y_mask: BitSet,
diff --git a/azalea-protocol/src/packets/game/clientbound_login_packet.rs b/azalea-protocol/src/packets/game/clientbound_login_packet.rs
index 9c8b7df1..b4a1b8d4 100755
--- a/azalea-protocol/src/packets/game/clientbound_login_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_login_packet.rs
@@ -1,7 +1,7 @@
use azalea_core::{game_type::GameType, resource_location::ResourceLocation};
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundLoginPacket {
pub player_id: u32,
pub hardcore: bool,
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 c9aff7cb..0fc0104a 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,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundMoveEntityPosPacket {
#[var]
pub entity_id: i32,
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 645912e7..5fde1b93 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,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundMoveEntityPosRotPacket {
#[var]
pub entity_id: i32,
diff --git a/azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs b/azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs
index 6ce0faa9..c8d0170b 100644
--- a/azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundMoveEntityRotPacket {
#[var]
pub entity_id: i32,
diff --git a/azalea-protocol/src/packets/game/clientbound_player_abilities_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_abilities_packet.rs
index cd645fe6..c3387f7f 100755
--- a/azalea-protocol/src/packets/game/clientbound_player_abilities_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_player_abilities_packet.rs
@@ -1,8 +1,8 @@
use crate::mc_buf::{McBufReadable, McBufWritable, Readable};
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
use std::io::{Read, Write};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundPlayerAbilitiesPacket {
pub flags: PlayerAbilitiesFlags,
pub flying_speed: f32,
@@ -34,16 +34,16 @@ impl McBufWritable for PlayerAbilitiesFlags {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
let mut byte = 0;
if self.invulnerable {
- byte = byte | 1;
+ byte |= 0b1;
}
if self.flying {
- byte = byte | 2;
+ byte |= 0b10;
}
if self.can_fly {
- byte = byte | 4;
+ byte |= 0b100;
}
if self.instant_break {
- byte = byte | 8;
+ byte |= 0b1000;
}
u8::write_into(&byte, buf)
}
diff --git a/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs
index 8e7ce4fd..cb17f1f5 100644
--- a/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs
@@ -1,10 +1,10 @@
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
use azalea_chat::component::Component;
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use packet_macros::{GamePacket, McBuf};
use std::io::{Read, Write};
use uuid::Uuid;
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundPlayerInfoPacket {
pub action: Action,
}
@@ -18,14 +18,14 @@ pub enum Action {
RemovePlayer(Vec),
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct PlayerProperty {
name: String,
value: String,
signature: Option,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct AddPlayer {
uuid: Uuid,
name: String,
@@ -37,26 +37,26 @@ pub struct AddPlayer {
display_name: Option,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct UpdateGameMode {
uuid: Uuid,
#[var]
gamemode: u32,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct UpdateLatency {
uuid: Uuid,
#[var]
ping: i32,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct UpdateDisplayName {
uuid: Uuid,
display_name: Option,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct RemovePlayer {
uuid: Uuid,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs b/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs
index 86266e9f..0457269a 100644
--- a/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs
@@ -1,8 +1,8 @@
use crate::mc_buf::{McBufReadable, McBufWritable, Readable};
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
use std::io::{Read, Write};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundPlayerPositionPacket {
pub x: f64,
pub y: f64,
@@ -43,19 +43,19 @@ impl McBufWritable for RelativeArguments {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
let mut byte = 0;
if self.x {
- byte = byte | 0b1;
+ byte |= 0b1;
}
if self.y {
- byte = byte | 0b10;
+ byte |= 0b10;
}
if self.z {
- byte = byte | 0b100;
+ byte |= 0b100;
}
if self.y_rot {
- byte = byte | 0b1000;
+ byte |= 0b1000;
}
if self.x_rot {
- byte = byte | 0b10000;
+ byte |= 0b10000;
}
u8::write_into(&byte, buf)
}
diff --git a/azalea-protocol/src/packets/game/clientbound_recipe_packet.rs b/azalea-protocol/src/packets/game/clientbound_recipe_packet.rs
index 543fb64c..e76504cc 100644
--- a/azalea-protocol/src/packets/game/clientbound_recipe_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_recipe_packet.rs
@@ -1,9 +1,9 @@
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
-use azalea_core::{resource_location::ResourceLocation, Slot};
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use azalea_core::resource_location::ResourceLocation;
+use packet_macros::{GamePacket, McBuf};
use std::io::{Read, Write};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundRecipePacket {
pub action: State,
pub settings: RecipeBookSettings,
@@ -11,7 +11,7 @@ pub struct ClientboundRecipePacket {
pub to_highlight: Vec,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct RecipeBookSettings {
pub gui_open: bool,
pub filtering_craftable: bool,
@@ -41,7 +41,7 @@ impl McBufWritable for State {
}
impl McBufReadable for State {
fn read_into(buf: &mut impl Read) -> Result {
- let state = buf.read_varint()?.try_into().unwrap();
+ let state = buf.read_varint()?;
Ok(match state {
0 => State::Init,
1 => State::Add,
diff --git a/azalea-protocol/src/packets/game/clientbound_remove_entities_packet.rs b/azalea-protocol/src/packets/game/clientbound_remove_entities_packet.rs
index 265d0c64..8f51596d 100644
--- a/azalea-protocol/src/packets/game/clientbound_remove_entities_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_remove_entities_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundRemoveEntitiesPacket {
#[var]
pub entity_ids: Vec,
diff --git a/azalea-protocol/src/packets/game/clientbound_rotate_head_packet.rs b/azalea-protocol/src/packets/game/clientbound_rotate_head_packet.rs
index d423885d..71b485ae 100644
--- a/azalea-protocol/src/packets/game/clientbound_rotate_head_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_rotate_head_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundRotateHeadPacket {
#[var]
pub entity_id: u32,
diff --git a/azalea-protocol/src/packets/game/clientbound_section_blocks_update_packet.rs b/azalea-protocol/src/packets/game/clientbound_section_blocks_update_packet.rs
new file mode 100644
index 00000000..6c429edb
--- /dev/null
+++ b/azalea-protocol/src/packets/game/clientbound_section_blocks_update_packet.rs
@@ -0,0 +1,43 @@
+use crate::mc_buf::{McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
+use azalea_core::{ChunkSectionBlockPos, ChunkSectionPos};
+use packet_macros::{GamePacket, McBuf};
+use std::io::{Read, Write};
+
+#[derive(Clone, Debug, McBuf, GamePacket)]
+pub struct ClientboundSectionBlocksUpdatePacket {
+ pub section_pos: ChunkSectionPos,
+ pub suppress_light_updates: bool,
+ pub states: Vec,
+}
+
+#[derive(Clone, Debug)]
+pub struct BlockStateWithPosition {
+ pub pos: ChunkSectionBlockPos,
+ pub state: u32,
+}
+
+impl McBufReadable for BlockStateWithPosition {
+ fn read_into(buf: &mut impl Read) -> Result {
+ let data = u64::var_read_into(buf)?;
+ let position_part = data & 4095;
+ let state = (data >> 12) as u32;
+ let position = ChunkSectionBlockPos {
+ x: (position_part >> 8 & 15) as u8,
+ y: (position_part >> 0 & 15) as u8,
+ z: (position_part >> 4 & 15) as u8,
+ };
+ Ok(BlockStateWithPosition {
+ pos: position,
+ state: state,
+ })
+ }
+}
+
+impl McBufWritable for BlockStateWithPosition {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ let data = (self.state as u64) << 12
+ | ((self.pos.x as u64) << 8 | (self.pos.z as u64) << 4 | (self.pos.y as u64));
+ u64::var_write_into(&data, buf)?;
+ Ok(())
+ }
+}
diff --git a/azalea-protocol/src/packets/game/clientbound_set_carried_item_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_carried_item_packet.rs
index 4f0bf575..003b6ccc 100755
--- a/azalea-protocol/src/packets/game/clientbound_set_carried_item_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_set_carried_item_packet.rs
@@ -1,7 +1,7 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
/// Sent to change the player's slot selection.
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundSetCarriedItemPacket {
pub slot: u8,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_set_chunk_cache_center.rs b/azalea-protocol/src/packets/game/clientbound_set_chunk_cache_center.rs
index f4d59e32..7557c16b 100644
--- a/azalea-protocol/src/packets/game/clientbound_set_chunk_cache_center.rs
+++ b/azalea-protocol/src/packets/game/clientbound_set_chunk_cache_center.rs
@@ -1,9 +1,9 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundSetChunkCacheCenterPacket {
#[var]
pub x: i32,
#[var]
- pub y: i32,
+ pub z: i32,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_set_default_spawn_position_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_default_spawn_position_packet.rs
index dad050cc..7ac42c5c 100644
--- a/azalea-protocol/src/packets/game/clientbound_set_default_spawn_position_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_set_default_spawn_position_packet.rs
@@ -1,7 +1,7 @@
use azalea_core::BlockPos;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundSetDefaultSpawnPositionPacket {
pub pos: BlockPos,
pub angle: f32,
diff --git a/azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs
index 752b7e6a..8a568689 100644
--- a/azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_set_entity_data_packet.rs
@@ -1,7 +1,7 @@
use crate::mc_buf::EntityMetadata;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundSetEntityDataPacket {
#[var]
pub id: i32,
diff --git a/azalea-protocol/src/packets/game/clientbound_set_entity_link_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_entity_link_packet.rs
index 7ee4a43c..e6e3af67 100644
--- a/azalea-protocol/src/packets/game/clientbound_set_entity_link_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_set_entity_link_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundSetEntityLinkPacket {
pub source_id: u32,
pub dest_id: u32,
diff --git a/azalea-protocol/src/packets/game/clientbound_set_experience_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_experience_packet.rs
index 88c306dc..bcb6393d 100644
--- a/azalea-protocol/src/packets/game/clientbound_set_experience_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_set_experience_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundSetExperiencePacket {
pub experience_progress: f32,
#[var]
diff --git a/azalea-protocol/src/packets/game/clientbound_set_health_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_health_packet.rs
index 136ef475..6c75cf63 100644
--- a/azalea-protocol/src/packets/game/clientbound_set_health_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_set_health_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundSetHealthPacket {
pub health: f32,
#[var]
diff --git a/azalea-protocol/src/packets/game/clientbound_set_time_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_time_packet.rs
index 02bf88d7..4cad0693 100644
--- a/azalea-protocol/src/packets/game/clientbound_set_time_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_set_time_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundSetTimePacket {
pub game_time: u64,
pub day_time: u64,
diff --git a/azalea-protocol/src/packets/game/clientbound_sound_packet.rs b/azalea-protocol/src/packets/game/clientbound_sound_packet.rs
index 67e832fe..797f03de 100644
--- a/azalea-protocol/src/packets/game/clientbound_sound_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_sound_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundSoundPacket {
#[var]
/// TODO: use the sound registry instead of just being a u32
@@ -13,7 +13,7 @@ pub struct ClientboundSoundPacket {
pub pitch: f32,
}
-#[derive(Clone, Debug, Copy, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, Copy, McBuf)]
pub enum SoundSource {
Master = 0,
Music = 1,
diff --git a/azalea-protocol/src/packets/game/clientbound_teleport_entity_packet.rs b/azalea-protocol/src/packets/game/clientbound_teleport_entity_packet.rs
index ea8788d6..c10db7b9 100644
--- a/azalea-protocol/src/packets/game/clientbound_teleport_entity_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_teleport_entity_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundTeleportEntityPacket {
#[var]
pub id: u32,
diff --git a/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs
index fe2c226d..daa1ac93 100644
--- a/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs
@@ -1,13 +1,13 @@
use crate::packets::{McBufReadable, McBufWritable};
use azalea_chat::component::Component;
use azalea_core::{resource_location::ResourceLocation, Slot};
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use packet_macros::{GamePacket, McBuf};
use std::{
collections::HashMap,
io::{Read, Write},
};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundUpdateAdvancementsPacket {
pub reset: bool,
pub added: HashMap,
@@ -15,7 +15,7 @@ pub struct ClientboundUpdateAdvancementsPacket {
pub progress: HashMap,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct Advancement {
parent_id: Option,
display: Option,
@@ -25,7 +25,7 @@ pub struct Advancement {
// requirements_strategy: RequirementsStrategy.AND
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct DisplayInfo {
pub title: Component,
pub description: Component,
@@ -71,7 +71,7 @@ impl McBufWritable for DisplayFlags {
}
}
-#[derive(Clone, Debug, Copy, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, Copy, McBuf)]
pub enum FrameType {
Task = 0,
Challenge = 1,
@@ -79,12 +79,12 @@ pub enum FrameType {
}
// nothing is written here
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct Criterion {}
pub type AdvancementProgress = HashMap;
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct CriterionProgress {
date: Option,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs
index 3d83e6fb..d0e7c9ee 100644
--- a/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs
@@ -1,24 +1,24 @@
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
use azalea_core::resource_location::ResourceLocation;
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use packet_macros::{GamePacket, McBuf};
use std::io::{Read, Write};
use uuid::Uuid;
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundUpdateAttributesPacket {
#[var]
pub entity_id: u32,
pub attributes: Vec,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct AttributeSnapshot {
pub attribute: ResourceLocation,
pub base: f64,
pub modifiers: Vec,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct Modifier {
pub uuid: Uuid,
pub amount: f64,
diff --git a/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
index 1c87a472..27839919 100644
--- a/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs
@@ -1,11 +1,11 @@
use std::io::{Read, Write};
use azalea_core::{resource_location::ResourceLocation, Slot};
-use packet_macros::{GamePacket, McBufReadable, McBufWritable};
+use packet_macros::{GamePacket, McBuf};
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundUpdateRecipesPacket {
pub recipes: Vec,
}
@@ -16,7 +16,7 @@ pub struct Recipe {
pub data: RecipeData,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct ShapelessRecipe {
/// Used to group similar recipes together in the recipe book.
/// Tag is present in recipe JSON
@@ -68,7 +68,7 @@ impl McBufReadable for ShapedRecipe {
}
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct CookingRecipe {
group: String,
ingredient: Ingredient,
@@ -77,13 +77,13 @@ pub struct CookingRecipe {
#[var]
cooking_time: u32,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct StoneCuttingRecipe {
group: String,
ingredient: Ingredient,
result: Slot,
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct SmithingRecipe {
base: Ingredient,
addition: Ingredient,
@@ -116,13 +116,13 @@ pub enum RecipeData {
Smithing(SmithingRecipe),
}
-#[derive(Clone, Debug, McBufReadable, McBufWritable)]
+#[derive(Clone, Debug, McBuf)]
pub struct Ingredient {
pub allowed: Vec,
}
impl McBufWritable for Recipe {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
todo!()
}
}
diff --git a/azalea-protocol/src/packets/game/clientbound_update_tags_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_tags_packet.rs
index f82a4177..60794f03 100755
--- a/azalea-protocol/src/packets/game/clientbound_update_tags_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_tags_packet.rs
@@ -1,12 +1,12 @@
use crate::mc_buf::{McBufReadable, McBufWritable, Readable, Writable};
use azalea_core::resource_location::ResourceLocation;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
use std::{
collections::HashMap,
io::{Read, Write},
};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundUpdateTagsPacket {
pub tags: HashMap>,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_update_view_distance_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_view_distance_packet.rs
index fe65d048..8288bd73 100755
--- a/azalea-protocol/src/packets/game/clientbound_update_view_distance_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_view_distance_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ClientboundUpdateViewDistancePacket {
#[var]
pub view_distance: i32,
diff --git a/azalea-protocol/src/packets/game/mod.rs b/azalea-protocol/src/packets/game/mod.rs
index 0391ee10..883e03aa 100755
--- a/azalea-protocol/src/packets/game/mod.rs
+++ b/azalea-protocol/src/packets/game/mod.rs
@@ -11,10 +11,12 @@ pub mod clientbound_declare_commands_packet;
pub mod clientbound_disconnect_packet;
pub mod clientbound_entity_event_packet;
pub mod clientbound_entity_velocity_packet;
+pub mod clientbound_game_event_packet;
pub mod clientbound_initialize_border_packet;
pub mod clientbound_keep_alive_packet;
pub mod clientbound_level_chunk_with_light_packet;
pub mod clientbound_level_event_packet;
+pub mod clientbound_level_particles_packet;
pub mod clientbound_light_update_packet;
pub mod clientbound_login_packet;
pub mod clientbound_move_entity_pos_packet;
@@ -26,6 +28,7 @@ pub mod clientbound_player_position_packet;
pub mod clientbound_recipe_packet;
pub mod clientbound_remove_entities_packet;
pub mod clientbound_rotate_head_packet;
+pub mod clientbound_section_blocks_update_packet;
pub mod clientbound_set_carried_item_packet;
pub mod clientbound_set_chunk_cache_center;
pub mod clientbound_set_default_spawn_position_packet;
@@ -56,19 +59,21 @@ declare_state_packets!(
0x00: clientbound_add_entity_packet::ClientboundAddEntityPacket,
0x02: clientbound_add_mob_packet::ClientboundAddMobPacket,
0x04: clientbound_add_player_packet::ClientboundAddPlayerPacket,
- 0x6: clientbound_animate_packet::ClientboundAnimatePacket,
- 0xc: clientbound_block_update_packet::ClientboundBlockUpdatePacket,
+ 0x06: clientbound_animate_packet::ClientboundAnimatePacket,
+ 0x0c: clientbound_block_update_packet::ClientboundBlockUpdatePacket,
0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket,
- 0xf: clientbound_chat_packet::ClientboundChatPacket,
+ 0x0f: clientbound_chat_packet::ClientboundChatPacket,
0x12: clientbound_declare_commands_packet::ClientboundDeclareCommandsPacket,
0x14: clientbound_container_set_content_packet::ClientboundContainerSetContentPacket,
0x1a: clientbound_disconnect_packet::ClientboundDisconnectPacket,
0x1b: clientbound_entity_event_packet::ClientboundEntityEventPacket,
0x18: clientbound_custom_payload_packet::ClientboundCustomPayloadPacket,
+ 0x1e: clientbound_game_event_packet::ClientboundGameEventPacket,
0x20: clientbound_initialize_border_packet::ClientboundInitializeBorderPacket,
0x21: clientbound_keep_alive_packet::ClientboundKeepAlivePacket,
0x22: clientbound_level_chunk_with_light_packet::ClientboundLevelChunkWithLightPacket,
0x23: clientbound_level_event_packet::ClientboundLevelEventPacket,
+ 0x24: clientbound_level_particles_packet::ClientboundLevelParticlesPacket,
0x25: clientbound_light_update_packet::ClientboundLightUpdatePacket,
0x26: clientbound_login_packet::ClientboundLoginPacket,
0x29: clientbound_move_entity_pos_packet::ClientboundMoveEntityPosPacket,
@@ -80,6 +85,7 @@ declare_state_packets!(
0x39: clientbound_recipe_packet::ClientboundRecipePacket,
0x3a: clientbound_remove_entities_packet::ClientboundRemoveEntitiesPacket,
0x3e: clientbound_rotate_head_packet::ClientboundRotateHeadPacket,
+ 0x3f: clientbound_section_blocks_update_packet::ClientboundSectionBlocksUpdatePacket,
0x48: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket,
0x49: clientbound_set_chunk_cache_center::ClientboundSetChunkCacheCenterPacket,
0x4a: clientbound_update_view_distance_packet::ClientboundUpdateViewDistancePacket,
diff --git a/azalea-protocol/src/packets/game/serverbound_custom_payload_packet.rs b/azalea-protocol/src/packets/game/serverbound_custom_payload_packet.rs
index eefafdd1..bef25b59 100644
--- a/azalea-protocol/src/packets/game/serverbound_custom_payload_packet.rs
+++ b/azalea-protocol/src/packets/game/serverbound_custom_payload_packet.rs
@@ -1,8 +1,8 @@
use crate::mc_buf::UnsizedByteArray;
use azalea_core::resource_location::ResourceLocation;
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ServerboundCustomPayloadPacket {
pub identifier: ResourceLocation,
pub data: UnsizedByteArray,
diff --git a/azalea-protocol/src/packets/game/serverbound_keep_alive_packet.rs b/azalea-protocol/src/packets/game/serverbound_keep_alive_packet.rs
index 740b18e3..c430499e 100644
--- a/azalea-protocol/src/packets/game/serverbound_keep_alive_packet.rs
+++ b/azalea-protocol/src/packets/game/serverbound_keep_alive_packet.rs
@@ -1,6 +1,6 @@
-use packet_macros::GamePacket;
+use packet_macros::{GamePacket, McBuf};
-#[derive(Clone, Debug, GamePacket)]
+#[derive(Clone, Debug, McBuf, GamePacket)]
pub struct ServerboundKeepAlivePacket {
pub id: u64,
}
diff --git a/azalea-protocol/src/packets/handshake/client_intention_packet.rs b/azalea-protocol/src/packets/handshake/client_intention_packet.rs
index 98caf34c..410c11ab 100755
--- a/azalea-protocol/src/packets/handshake/client_intention_packet.rs
+++ b/azalea-protocol/src/packets/handshake/client_intention_packet.rs
@@ -1,8 +1,8 @@
use crate::packets::ConnectionProtocol;
-use packet_macros::HandshakePacket;
+use packet_macros::{HandshakePacket, McBuf};
use std::hash::Hash;
-#[derive(Hash, Clone, Debug, HandshakePacket)]
+#[derive(Hash, Clone, Debug, McBuf, HandshakePacket)]
pub struct ClientIntentionPacket {
#[var]
pub protocol_version: u32,
diff --git a/azalea-protocol/src/packets/login/clientbound_custom_query_packet.rs b/azalea-protocol/src/packets/login/clientbound_custom_query_packet.rs
index fc5dd1a2..1b1da87a 100755
--- a/azalea-protocol/src/packets/login/clientbound_custom_query_packet.rs
+++ b/azalea-protocol/src/packets/login/clientbound_custom_query_packet.rs
@@ -1,9 +1,9 @@
use crate::mc_buf::UnsizedByteArray;
use azalea_core::resource_location::ResourceLocation;
-use packet_macros::LoginPacket;
+use packet_macros::{LoginPacket, McBuf};
use std::hash::Hash;
-#[derive(Hash, Clone, Debug, LoginPacket)]
+#[derive(Hash, Clone, Debug, McBuf, LoginPacket)]
pub struct ClientboundCustomQueryPacket {
#[var]
pub transaction_id: u32,
diff --git a/azalea-protocol/src/packets/login/clientbound_login_disconnect_packet.rs b/azalea-protocol/src/packets/login/clientbound_login_disconnect_packet.rs
index 28d91c79..9ab09e3b 100644
--- a/azalea-protocol/src/packets/login/clientbound_login_disconnect_packet.rs
+++ b/azalea-protocol/src/packets/login/clientbound_login_disconnect_packet.rs
@@ -1,7 +1,7 @@
use azalea_chat::component::Component;
-use packet_macros::LoginPacket;
+use packet_macros::{LoginPacket, McBuf};
-#[derive(Clone, Debug, LoginPacket)]
+#[derive(Clone, Debug, McBuf, LoginPacket)]
pub struct ClientboundLoginDisconnectPacket {
pub reason: Component,
}
diff --git a/azalea-protocol/src/packets/login/serverbound_hello_packet.rs b/azalea-protocol/src/packets/login/serverbound_hello_packet.rs
index eb6a4065..5cb660ed 100755
--- a/azalea-protocol/src/packets/login/serverbound_hello_packet.rs
+++ b/azalea-protocol/src/packets/login/serverbound_hello_packet.rs
@@ -1,7 +1,7 @@
-use packet_macros::LoginPacket;
+use packet_macros::{LoginPacket, McBuf};
use std::hash::Hash;
-#[derive(Hash, Clone, Debug, LoginPacket)]
+#[derive(Hash, Clone, Debug, McBuf, LoginPacket)]
pub struct ServerboundHelloPacket {
pub username: String,
}
diff --git a/azalea-protocol/src/packets/login/serverbound_key_packet.rs b/azalea-protocol/src/packets/login/serverbound_key_packet.rs
index f402d357..9100823d 100644
--- a/azalea-protocol/src/packets/login/serverbound_key_packet.rs
+++ b/azalea-protocol/src/packets/login/serverbound_key_packet.rs
@@ -1,9 +1,7 @@
-use super::LoginPacket;
-use crate::mc_buf::Writable;
-use packet_macros::LoginPacket;
+use packet_macros::{LoginPacket, McBuf};
use std::hash::Hash;
-#[derive(Hash, Clone, Debug, LoginPacket)]
+#[derive(Hash, Clone, Debug, McBuf, LoginPacket)]
pub struct ServerboundKeyPacket {
pub shared_secret: Vec,
pub nonce: Vec,
diff --git a/azalea-protocol/src/packets/mod.rs b/azalea-protocol/src/packets/mod.rs
index a706646d..16e97068 100755
--- a/azalea-protocol/src/packets/mod.rs
+++ b/azalea-protocol/src/packets/mod.rs
@@ -43,7 +43,7 @@ where
fn write(&self, buf: &mut impl Write) -> Result<(), std::io::Error>;
}
-impl McBufReadable for ConnectionProtocol {
+impl crate::mc_buf::McBufReadable for ConnectionProtocol {
fn read_into(buf: &mut impl Read) -> Result {
ConnectionProtocol::from_i32(buf.read_varint()?)
.ok_or_else(|| "Invalid intention".to_string())
diff --git a/azalea-protocol/src/packets/status/serverbound_status_request_packet.rs b/azalea-protocol/src/packets/status/serverbound_status_request_packet.rs
index c15673d9..3369e6a9 100755
--- a/azalea-protocol/src/packets/status/serverbound_status_request_packet.rs
+++ b/azalea-protocol/src/packets/status/serverbound_status_request_packet.rs
@@ -1,4 +1,4 @@
-use packet_macros::StatusPacket;
+use packet_macros::{McBuf, StatusPacket};
-#[derive(Clone, Debug, StatusPacket)]
+#[derive(Clone, Debug, McBuf, StatusPacket)]
pub struct ServerboundStatusRequestPacket {}
diff --git a/azalea-protocol/src/write.rs b/azalea-protocol/src/write.rs
index 345829c5..9291681c 100755
--- a/azalea-protocol/src/write.rs
+++ b/azalea-protocol/src/write.rs
@@ -2,10 +2,7 @@ use crate::{mc_buf::Writable, packets::ProtocolPacket, read::MAXIMUM_UNCOMPRESSE
use async_compression::tokio::bufread::ZlibEncoder;
use azalea_crypto::Aes128CfbEnc;
use std::fmt::Debug;
-use tokio::{
- io::{AsyncReadExt, AsyncWrite, AsyncWriteExt},
- net::TcpStream,
-};
+use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
fn frame_prepender(data: &mut Vec) -> Result, String> {
let mut buf = Vec::new();
diff --git a/azalea-world/Cargo.toml b/azalea-world/Cargo.toml
new file mode 100644
index 00000000..e8d81ac3
--- /dev/null
+++ b/azalea-world/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+edition = "2021"
+name = "azalea-world"
+version = "0.1.0"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+azalea-core = {path = "../azalea-core"}
+azalea-nbt = {path = "../azalea-nbt"}
+azalea-protocol = {path = "../azalea-protocol"}
diff --git a/azalea-world/README.md b/azalea-world/README.md
new file mode 100644
index 00000000..6f68ab42
--- /dev/null
+++ b/azalea-world/README.md
@@ -0,0 +1,3 @@
+# Azalea World
+
+The Minecraft world representation used in Azalea.
diff --git a/azalea-world/src/bit_storage.rs b/azalea-world/src/bit_storage.rs
new file mode 100644
index 00000000..aba52aef
--- /dev/null
+++ b/azalea-world/src/bit_storage.rs
@@ -0,0 +1,209 @@
+use std::{error::Error, fmt};
+
+// this is from minecraft's code
+// yeah idk either
+const MAGIC: [(i32, i32, i32); 64] = [
+ (-1, -1, 0),
+ (-2147483648, 0, 0),
+ (1431655765, 1431655765, 0),
+ (-2147483648, 0, 1),
+ (858993459, 858993459, 0),
+ (715827882, 715827882, 0),
+ (613566756, 613566756, 0),
+ (-2147483648, 0, 2),
+ (477218588, 477218588, 0),
+ (429496729, 429496729, 0),
+ (390451572, 390451572, 0),
+ (357913941, 357913941, 0),
+ (330382099, 330382099, 0),
+ (306783378, 306783378, 0),
+ (286331153, 286331153, 0),
+ (-2147483648, 0, 3),
+ (252645135, 252645135, 0),
+ (238609294, 238609294, 0),
+ (226050910, 226050910, 0),
+ (214748364, 214748364, 0),
+ (204522252, 204522252, 0),
+ (195225786, 195225786, 0),
+ (186737708, 186737708, 0),
+ (178956970, 178956970, 0),
+ (171798691, 171798691, 0),
+ (165191049, 165191049, 0),
+ (159072862, 159072862, 0),
+ (153391689, 153391689, 0),
+ (148102320, 148102320, 0),
+ (143165576, 143165576, 0),
+ (138547332, 138547332, 0),
+ (-2147483648, 0, 4),
+ (130150524, 130150524, 0),
+ (126322567, 126322567, 0),
+ (122713351, 122713351, 0),
+ (119304647, 119304647, 0),
+ (116080197, 116080197, 0),
+ (113025455, 113025455, 0),
+ (110127366, 110127366, 0),
+ (107374182, 107374182, 0),
+ (104755299, 104755299, 0),
+ (102261126, 102261126, 0),
+ (99882960, 99882960, 0),
+ (97612893, 97612893, 0),
+ (95443717, 95443717, 0),
+ (93368854, 93368854, 0),
+ (91382282, 91382282, 0),
+ (89478485, 89478485, 0),
+ (87652393, 87652393, 0),
+ (85899345, 85899345, 0),
+ (84215045, 84215045, 0),
+ (82595524, 82595524, 0),
+ (81037118, 81037118, 0),
+ (79536431, 79536431, 0),
+ (78090314, 78090314, 0),
+ (76695844, 76695844, 0),
+ (75350303, 75350303, 0),
+ (74051160, 74051160, 0),
+ (72796055, 72796055, 0),
+ (71582788, 71582788, 0),
+ (70409299, 70409299, 0),
+ (69273666, 69273666, 0),
+ (68174084, 68174084, 0),
+ (-2147483648, 0, 5),
+];
+
+/// A compact list of integers with the given number of bits per entry.
+#[derive(Clone, Debug, Default)]
+pub struct BitStorage {
+ pub data: Vec,
+ bits: usize,
+ mask: u64,
+ size: usize,
+ values_per_long: u8,
+ divide_mul: i32,
+ divide_add: i32,
+ divide_shift: i32,
+}
+
+#[derive(Debug)]
+pub enum BitStorageError {
+ InvalidLength { got: usize, expected: usize },
+}
+impl fmt::Display for BitStorageError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ BitStorageError::InvalidLength { got, expected } => write!(
+ f,
+ "Invalid length given for storage, got: {}, but expected: {}",
+ got, expected
+ ),
+ }
+ }
+}
+impl Error for BitStorageError {}
+
+impl BitStorage {
+ /// Create a new BitStorage with the given number of bits per entry.
+ /// `size` is the number of entries in the BitStorage.
+ pub fn new(bits: usize, size: usize, data: Option>) -> Result {
+ // vanilla has this assert but it's not always true for some reason??
+ // assert!(bits >= 1 && bits <= 32);
+
+ if let Some(data) = &data {
+ if data.len() == 0 {
+ // TODO: make 0 bit storage actually work
+ return Ok(BitStorage::default());
+ }
+ }
+
+ let values_per_long = 64 / bits;
+ let magic_index = values_per_long - 1;
+ let (divide_mul, divide_add, divide_shift) = MAGIC[magic_index as usize];
+ let calculated_length = (size + values_per_long - 1) / values_per_long;
+
+ let mask = (1 << bits) - 1;
+
+ let using_data = if let Some(data) = data {
+ if data.len() != calculated_length as usize {
+ return Err(BitStorageError::InvalidLength {
+ got: data.len(),
+ expected: calculated_length as usize,
+ });
+ }
+ data
+ } else {
+ vec![0; calculated_length as usize]
+ };
+
+ Ok(BitStorage {
+ data: using_data,
+ bits,
+ mask,
+ size,
+ values_per_long: values_per_long as u8,
+ divide_mul,
+ divide_add,
+ divide_shift,
+ })
+ }
+
+ pub fn cell_index(&self, index: u64) -> usize {
+ // as unsigned wrap
+ let first = self.divide_mul as u32 as u64;
+ let second = self.divide_add as u64;
+
+ (((index * first) + second) >> 32 >> self.divide_shift)
+ .try_into()
+ .unwrap()
+ }
+
+ pub fn get(&self, index: usize) -> u64 {
+ // Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)var1);
+ // int var2 = this.cellIndex(var1);
+ // long var3 = this.data[var2];
+ // int var5 = (var1 - var2 * this.valuesPerLong) * this.bits;
+ // return (int)(var3 >> var5 & this.mask);
+
+ assert!(
+ index <= self.size - 1,
+ "Index {} out of bounds (max is {})",
+ index,
+ self.size - 1
+ );
+ let cell_index = self.cell_index(index as u64);
+ let cell = &self.data[cell_index as usize];
+ let bit_index = (index - cell_index * self.values_per_long as usize) * self.bits;
+ cell >> bit_index & self.mask
+ }
+
+ pub fn set(&mut self, index: usize, value: u64) {
+ // Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)var1);
+ // Validate.inclusiveBetween(0L, this.mask, (long)var2);
+ // int var3 = this.cellIndex(var1);
+ // long var4 = this.data[var3];
+ // int var6 = (var1 - var3 * this.valuesPerLong) * this.bits;
+ // this.data[var3] = var4 & ~(this.mask << var6) | ((long)var2 & this.mask) << var6;
+
+ assert!(index <= self.size - 1);
+ assert!(value <= self.mask);
+ let cell_index = self.cell_index(index as u64);
+ let cell = &mut self.data[cell_index as usize];
+ let bit_index = (index - cell_index * self.values_per_long as usize) * self.bits;
+ *cell = *cell & !(self.mask << bit_index) | (value & self.mask) << bit_index;
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_wikivg_example() {
+ let data = [
+ 1, 2, 2, 3, 4, 4, 5, 6, 6, 4, 8, 0, 7, 4, 3, 13, 15, 16, 9, 14, 10, 12, 0, 2,
+ ];
+ let compact_data: [u64; 2] = [0x0020863148418841, 0x01018A7260F68C87];
+ let storage = BitStorage::new(5, data.len(), Some(compact_data.to_vec())).unwrap();
+
+ for (i, expected) in data.iter().enumerate() {
+ assert_eq!(storage.get(i), *expected);
+ }
+ }
+}
diff --git a/azalea-world/src/lib.rs b/azalea-world/src/lib.rs
new file mode 100644
index 00000000..766c61f0
--- /dev/null
+++ b/azalea-world/src/lib.rs
@@ -0,0 +1,237 @@
+#![feature(int_roundings)]
+
+mod bit_storage;
+mod palette;
+
+use crate::palette::PalettedContainerType;
+use azalea_core::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos};
+use azalea_protocol::mc_buf::{McBufReadable, McBufWritable};
+pub use bit_storage::BitStorage;
+use palette::PalettedContainer;
+use std::{
+ io::{Read, Write},
+ ops::{Index, IndexMut},
+ sync::{Arc, Mutex},
+};
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn it_works() {
+ let result = 2 + 2;
+ assert_eq!(result, 4);
+ }
+}
+
+const SECTION_HEIGHT: u32 = 16;
+
+pub struct World {
+ pub storage: ChunkStorage,
+ pub height: u32,
+ pub min_y: i32,
+}
+
+impl World {
+ pub fn replace_with_packet_data(
+ &mut self,
+ pos: &ChunkPos,
+ data: &mut impl Read,
+ ) -> Result<(), String> {
+ if !self.storage.in_range(pos) {
+ println!(
+ "Ignoring chunk since it's not in the view range: {}, {}",
+ pos.x, pos.z
+ );
+ return Ok(());
+ }
+ // let existing_chunk = &self.storage[pos];
+
+ let chunk = Arc::new(Mutex::new(Chunk::read_with_world(data, self)?));
+ println!("Loaded chunk {:?}", pos);
+ self.storage[pos] = Some(chunk);
+
+ Ok(())
+ }
+
+ pub fn update_view_center(&mut self, pos: &ChunkPos) {
+ self.storage.view_center = *pos;
+ }
+
+ pub fn get_block_state(&self, pos: &BlockPos) -> Option {
+ self.storage.get_block_state(pos, self.min_y)
+ }
+}
+impl Index<&ChunkPos> for World {
+ type Output = Option>>;
+
+ fn index(&self, pos: &ChunkPos) -> &Self::Output {
+ &self.storage[pos]
+ }
+}
+impl IndexMut<&ChunkPos> for World {
+ fn index_mut<'a>(&'a mut self, pos: &ChunkPos) -> &'a mut Self::Output {
+ &mut self.storage[pos]
+ }
+}
+// impl Index<&BlockPos> for World {
+// type Output = Option>>;
+
+// fn index(&self, pos: &BlockPos) -> &Self::Output {
+// let chunk = &self[ChunkPos::from(pos)];
+// // chunk.
+
+// }
+// }
+
+pub struct ChunkStorage {
+ view_center: ChunkPos,
+ chunk_radius: u32,
+ view_range: u32,
+ // chunks is a list of size chunk_radius * chunk_radius
+ chunks: Vec