diff options
| author | mat <github@matdoes.dev> | 2022-05-08 18:55:49 -0500 |
|---|---|---|
| committer | mat <github@matdoes.dev> | 2022-05-08 18:55:49 -0500 |
| commit | ac392542ce223639c8615035a0be050fff12030a (patch) | |
| tree | 460f8019c2a7aeada10a714f624002ef53007be2 /azalea-protocol/src | |
| parent | e0239865659b2f2750edda7556548f6a2b8d4127 (diff) | |
| parent | d783a0295b11c32f1b5425cab2461f9297f7f8fa (diff) | |
| download | azalea-drasl-ac392542ce223639c8615035a0be050fff12030a.tar.xz | |
Merge branch 'main' into chunk-decoding
Diffstat (limited to 'azalea-protocol/src')
42 files changed, 942 insertions, 501 deletions
diff --git a/azalea-protocol/src/connect.rs b/azalea-protocol/src/connect.rs index e9d898d6..67771d8e 100755 --- a/azalea-protocol/src/connect.rs +++ b/azalea-protocol/src/connect.rs @@ -10,6 +10,7 @@ use crate::ServerIpAddress; use azalea_crypto::{Aes128CfbDec, Aes128CfbEnc}; use tokio::net::TcpStream; +#[derive(Debug, Clone, Copy)] pub enum PacketFlow { ClientToServer, ServerToClient, diff --git a/azalea-protocol/src/mc_buf/definitions.rs b/azalea-protocol/src/mc_buf/definitions.rs new file mode 100644 index 00000000..a59fc574 --- /dev/null +++ b/azalea-protocol/src/mc_buf/definitions.rs @@ -0,0 +1,435 @@ +use crate::mc_buf::read::{McBufReadable, Readable}; +use crate::mc_buf::write::{McBufWritable, Writable}; +use azalea_chat::component::Component; +use azalea_core::{BlockPos, Direction, Slot}; +use packet_macros::{McBufReadable, McBufWritable}; +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, McBufReadable, McBufWritable)] +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, McBufReadable, McBufWritable)] +pub enum Pose { + Standing = 0, + FallFlying = 1, + Sleeping = 2, + Swimming = 3, + SpinAttack = 4, + Sneaking = 5, + LongJumping = 6, + Dying = 7, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct VillagerData { + #[var] + type_: u32, + #[var] + profession: u32, + #[var] + level: u32, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct Particle { + #[var] + pub id: i32, + pub data: ParticleData, +} + +#[derive(Clone, Debug)] +pub enum ParticleData { + AmbientEntityEffect, + AngryVillager, + Block(BlockParticle), + BlockMarker(BlockParticle), + Bubble, + Cloud, + Crit, + DamageIndicator, + DragonBreath, + DrippingLava, + FallingLava, + LandingLava, + DrippingWater, + FallingWater, + Dust(DustParticle), + DustColorTransition(DustColorTransitionParticle), + Effect, + ElderGuardian, + EnchantedHit, + Enchant, + EndRod, + EntityEffect, + ExplosionEmitter, + Explosion, + FallingDust(BlockParticle), + Firework, + Fishing, + Flame, + SoulFireFlame, + Soul, + Flash, + HappyVillager, + Composter, + Heart, + InstantEffect, + Item(ItemParticle), + Vibration(VibrationParticle), + ItemSlime, + ItemSnowball, + LargeSmoke, + Lava, + Mycelium, + Note, + Poof, + Portal, + Rain, + Smoke, + Sneeze, + Spit, + SquidInk, + SweepAttack, + TotemOfUndying, + Underwater, + Splash, + Witch, + BubblePop, + CurrentDown, + BubbleColumnUp, + Nautilus, + Dolphin, + CampfireCozySmoke, + CampfireSignalSmoke, + DrippingHoney, + FallingHoney, + LandingHoney, + FallingNectar, + FallingSporeBlossom, + Ash, + CrimsonSpore, + WarpedSpore, + SporeBlossomAir, + DrippingObsidianTear, + FallingObsidianTear, + LandingObsidianTear, + ReversePortal, + WhiteAsh, + SmallFlame, + Snowflake, + DrippingDripstoneLava, + FallingDripstoneLava, + DrippingDripstoneWater, + FallingDripstoneWater, + GlowSquidInk, + Glow, + WaxOn, + WaxOff, + ElectricSpark, + Scrape, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct BlockParticle { + #[var] + pub block_state: i32, +} +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct DustParticle { + /// Red value, 0-1 + pub red: f32, + /// Green value, 0-1 + pub green: f32, + /// Blue value, 0-1 + pub blue: f32, + /// The scale, will be clamped between 0.01 and 4. + pub scale: f32, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct DustColorTransitionParticle { + /// Red value, 0-1 + pub from_red: f32, + /// Green value, 0-1 + pub from_green: f32, + /// Blue value, 0-1 + pub from_blue: f32, + /// The scale, will be clamped between 0.01 and 4. + pub scale: f32, + /// Red value, 0-1 + pub to_red: f32, + /// Green value, 0-1 + pub to_green: f32, + /// Blue value, 0-1 + pub to_blue: f32, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct ItemParticle { + pub item: Slot, +} + +#[derive(Debug, Clone, McBufReadable, McBufWritable)] +pub struct VibrationParticle { + pub origin: BlockPos, + pub position_type: String, + pub block_position: BlockPos, + #[var] + pub entity_id: u32, + #[var] + pub ticks: u32, +} + +impl McBufReadable for ParticleData { + fn read_into(buf: &mut impl Read) -> Result<Self, String> { + let id = buf.read_varint()?; + Ok(match id { + 0 => ParticleData::AmbientEntityEffect, + 1 => ParticleData::AngryVillager, + 2 => ParticleData::Block(BlockParticle::read_into(buf)?), + 3 => ParticleData::BlockMarker(BlockParticle::read_into(buf)?), + 4 => ParticleData::Bubble, + 5 => ParticleData::Cloud, + 6 => ParticleData::Crit, + 7 => ParticleData::DamageIndicator, + 8 => ParticleData::DragonBreath, + 9 => ParticleData::DrippingLava, + 10 => ParticleData::FallingLava, + 11 => ParticleData::LandingLava, + 12 => ParticleData::DrippingWater, + 13 => ParticleData::FallingWater, + 14 => ParticleData::Dust(DustParticle::read_into(buf)?), + 15 => ParticleData::DustColorTransition(DustColorTransitionParticle::read_into(buf)?), + 16 => ParticleData::Effect, + 17 => ParticleData::ElderGuardian, + 18 => ParticleData::EnchantedHit, + 19 => ParticleData::Enchant, + 20 => ParticleData::EndRod, + 21 => ParticleData::EntityEffect, + 22 => ParticleData::ExplosionEmitter, + 23 => ParticleData::Explosion, + 24 => ParticleData::FallingDust(BlockParticle::read_into(buf)?), + 25 => ParticleData::Firework, + 26 => ParticleData::Fishing, + 27 => ParticleData::Flame, + 28 => ParticleData::SoulFireFlame, + 29 => ParticleData::Soul, + 30 => ParticleData::Flash, + 31 => ParticleData::HappyVillager, + 32 => ParticleData::Composter, + 33 => ParticleData::Heart, + 34 => ParticleData::InstantEffect, + 35 => ParticleData::Item(ItemParticle::read_into(buf)?), + 36 => ParticleData::Vibration(VibrationParticle::read_into(buf)?), + 37 => ParticleData::ItemSlime, + 38 => ParticleData::ItemSnowball, + 39 => ParticleData::LargeSmoke, + 40 => ParticleData::Lava, + 41 => ParticleData::Mycelium, + 42 => ParticleData::Note, + 43 => ParticleData::Poof, + 44 => ParticleData::Portal, + 45 => ParticleData::Rain, + 46 => ParticleData::Smoke, + 47 => ParticleData::Sneeze, + 48 => ParticleData::Spit, + 49 => ParticleData::SquidInk, + 50 => ParticleData::SweepAttack, + 51 => ParticleData::TotemOfUndying, + 52 => ParticleData::Underwater, + 53 => ParticleData::Splash, + 54 => ParticleData::Witch, + 55 => ParticleData::BubblePop, + 56 => ParticleData::CurrentDown, + 57 => ParticleData::BubbleColumnUp, + 58 => ParticleData::Nautilus, + 59 => ParticleData::Dolphin, + 60 => ParticleData::CampfireCozySmoke, + 61 => ParticleData::CampfireSignalSmoke, + 62 => ParticleData::DrippingHoney, + 63 => ParticleData::FallingHoney, + 64 => ParticleData::LandingHoney, + 65 => ParticleData::FallingNectar, + 66 => ParticleData::FallingSporeBlossom, + 67 => ParticleData::Ash, + 68 => ParticleData::CrimsonSpore, + 69 => ParticleData::WarpedSpore, + 70 => ParticleData::SporeBlossomAir, + 71 => ParticleData::DrippingObsidianTear, + 72 => ParticleData::FallingObsidianTear, + 73 => ParticleData::LandingObsidianTear, + 74 => ParticleData::ReversePortal, + 75 => ParticleData::WhiteAsh, + 76 => ParticleData::SmallFlame, + 77 => ParticleData::Snowflake, + 78 => ParticleData::DrippingDripstoneLava, + 79 => ParticleData::FallingDripstoneLava, + 80 => ParticleData::DrippingDripstoneWater, + 81 => ParticleData::FallingDripstoneWater, + 82 => ParticleData::GlowSquidInk, + 83 => ParticleData::Glow, + 84 => ParticleData::WaxOn, + 85 => ParticleData::WaxOff, + 86 => ParticleData::ElectricSpark, + 87 => ParticleData::Scrape, + _ => return Err(format!("Unknown particle id: {}", 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 index debf2991..94e4af0b 100755..100644 --- a/azalea-protocol/src/mc_buf/mod.rs +++ b/azalea-protocol/src/mc_buf/mod.rs @@ -1,12 +1,14 @@ //! Utilities for reading and writing for the Minecraft protocol +mod definitions; mod read; mod write; +pub use definitions::{BitSet, EntityMetadata, UnsizedByteArray}; use packet_macros::{McBufReadable, McBufWritable}; -pub use read::{read_varint_async, McBufReadable, McBufVarintReadable, Readable}; +pub use read::{read_varint_async, McBufReadable, McBufVarReadable, Readable}; use std::ops::Deref; -pub use write::{McBufVarintWritable, McBufWritable, Writable}; +pub use write::{McBufVarWritable, McBufWritable, Writable}; // const DEFAULT_NBT_QUOTA: u32 = 2097152; const MAX_STRING_LENGTH: u16 = 32767; @@ -16,43 +18,6 @@ const MAX_STRING_LENGTH: u16 = 32767; // TODO: have a definitions.rs in mc_buf that contains UnsizedByteArray and BitSet -/// 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, McBufReadable, McBufWritable)] -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 - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/azalea-protocol/src/mc_buf/read.rs b/azalea-protocol/src/mc_buf/read.rs index a8c44bdf..ebafad92 100755..100644 --- a/azalea-protocol/src/mc_buf/read.rs +++ b/azalea-protocol/src/mc_buf/read.rs @@ -6,7 +6,7 @@ use azalea_core::{ }; use byteorder::{ReadBytesExt, BE}; use serde::Deserialize; -use std::io::Read; +use std::{collections::HashMap, hash::Hash, io::Read}; use tokio::io::{AsyncRead, AsyncReadExt}; use uuid::Uuid; @@ -236,11 +236,11 @@ where fn read_into(buf: &mut impl Read) -> Result<Self, String>; } -pub trait McBufVarintReadable +pub trait McBufVarReadable where Self: Sized, { - fn varint_read_into(buf: &mut impl Read) -> Result<Self, String>; + fn var_read_into(buf: &mut impl Read) -> Result<Self, String>; } impl McBufReadable for i32 { @@ -249,26 +249,37 @@ impl McBufReadable for i32 { } } -impl McBufVarintReadable for i32 { - fn varint_read_into(buf: &mut impl Read) -> Result<Self, String> { +impl McBufVarReadable for i32 { + fn var_read_into(buf: &mut impl Read) -> Result<Self, String> { buf.read_varint() } } -impl<T: McBufVarintReadable> McBufVarintReadable for Vec<T> { - fn varint_read_into(buf: &mut impl Read) -> Result<Self, String> { - let length = u32::varint_read_into(buf)?; - let mut vec = Vec::with_capacity(length as usize); - for _ in 0..length { - vec.push(T::varint_read_into(buf)?); +impl McBufVarReadable for i64 { + // fast varints modified from https://github.com/luojia65/mc-varint/blob/master/src/lib.rs#L54 + fn var_read_into(buf: &mut impl Read) -> Result<Self, String> { + let mut buffer = [0]; + let mut ans = 0; + for i in 0..8 { + buf.read_exact(&mut buffer) + .map_err(|_| "Invalid VarLong".to_string())?; + ans |= ((buffer[0] & 0b0111_1111) as i64) << 7 * i; + if buffer[0] & 0b1000_0000 == 0 { + break; + } } - Ok(vec) + Ok(ans) + } +} +impl McBufVarReadable for u64 { + fn var_read_into(buf: &mut impl Read) -> Result<Self, String> { + i64::var_read_into(buf).map(|i| i as u64) } } impl McBufReadable for UnsizedByteArray { fn read_into(buf: &mut impl Read) -> Result<Self, String> { - Ok(UnsizedByteArray(buf.read_bytes()?)) + Ok(buf.read_bytes()?.into()) } } @@ -283,6 +294,17 @@ impl<T: McBufReadable + Send> McBufReadable for Vec<T> { } } +impl<K: McBufReadable + Send + Eq + Hash, V: McBufReadable + Send> McBufReadable for HashMap<K, V> { + default fn read_into(buf: &mut impl Read) -> Result<Self, String> { + let length = buf.read_varint()? as usize; + let mut contents = HashMap::with_capacity(length); + for _ in 0..length { + contents.insert(K::read_into(buf)?, V::read_into(buf)?); + } + Ok(contents) + } +} + impl McBufReadable for Vec<u8> { fn read_into(buf: &mut impl Read) -> Result<Self, String> { buf.read_byte_array() @@ -311,8 +333,8 @@ impl McBufReadable for u32 { } // u32 varint -impl McBufVarintReadable for u32 { - fn varint_read_into(buf: &mut impl Read) -> Result<Self, String> { +impl McBufVarReadable for u32 { + fn var_read_into(buf: &mut impl Read) -> Result<Self, String> { buf.read_varint().map(|i| i as u32) } } @@ -332,12 +354,24 @@ impl McBufReadable for i16 { } // u16 varint -impl McBufVarintReadable for u16 { - fn varint_read_into(buf: &mut impl Read) -> Result<Self, String> { +impl McBufVarReadable for u16 { + fn var_read_into(buf: &mut impl Read) -> Result<Self, String> { buf.read_varint().map(|i| i as u16) } } +// Vec<T> varint +impl<T: McBufVarReadable> McBufVarReadable for Vec<T> { + fn var_read_into(buf: &mut impl Read) -> Result<Self, String> { + let length = buf.read_varint()? as usize; + let mut contents = Vec::with_capacity(length); + for _ in 0..length { + contents.push(T::var_read_into(buf)?); + } + Ok(contents) + } +} + // i64 impl McBufReadable for i64 { fn read_into(buf: &mut impl Read) -> Result<Self, String> { diff --git a/azalea-protocol/src/mc_buf/write.rs b/azalea-protocol/src/mc_buf/write.rs index cc5f2284..7fe61752 100755..100644 --- a/azalea-protocol/src/mc_buf/write.rs +++ b/azalea-protocol/src/mc_buf/write.rs @@ -5,7 +5,7 @@ use azalea_core::{ serializable_uuid::SerializableUuid, BlockPos, Direction, Slot, }; use byteorder::{BigEndian, WriteBytesExt}; -use std::io::Write; +use std::{collections::HashMap, io::Write}; use uuid::Uuid; pub trait Writable: Write { @@ -146,8 +146,8 @@ pub trait McBufWritable { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error>; } -pub trait McBufVarintWritable { - fn varint_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error>; +pub trait McBufVarWritable { + fn var_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error>; } impl McBufWritable for i32 { @@ -156,8 +156,8 @@ impl McBufWritable for i32 { } } -impl McBufVarintWritable for i32 { - fn varint_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { +impl McBufVarWritable for i32 { + fn var_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { buf.write_varint(*self) } } @@ -168,14 +168,24 @@ impl McBufWritable for UnsizedByteArray { } } -// TODO: use specialization when that gets stabilized into rust -// to optimize for Vec<u8> byte arrays impl<T: McBufWritable> McBufWritable for Vec<T> { default fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { buf.write_list(self, |buf, i| T::write_into(i, buf)) } } +impl<K: McBufWritable, V: McBufWritable> McBufWritable for HashMap<K, V> { + default fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + u32::var_write_into(&(self.len() as u32), buf)?; + for (key, value) in self { + key.write_into(buf)?; + value.write_into(buf)?; + } + + Ok(()) + } +} + impl McBufWritable for Vec<u8> { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { buf.write_byte_array(self) @@ -204,16 +214,32 @@ impl McBufWritable for u32 { } // u32 varint -impl McBufVarintWritable for u32 { - fn varint_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { - i32::varint_write_into(&(*self as i32), buf) +impl McBufVarWritable for u32 { + fn var_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + i32::var_write_into(&(*self as i32), buf) } } -// Vec<T> varint -impl<T: McBufVarintWritable> McBufVarintWritable for Vec<T> { - fn varint_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { - buf.write_list(self, |buf, i| i.varint_write_into(buf)) +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; + value = (value >> 7) & (i64::max_value() >> 6); + if value != 0 { + buffer[0] |= 0b1000_0000; + } + cnt += buf.write(&mut buffer)?; + } + Ok(()) + } +} + +impl McBufVarWritable for u64 { + fn var_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + i64::var_write_into(&(*self as i64), buf) } } @@ -225,9 +251,20 @@ impl McBufWritable for u16 { } // u16 varint -impl McBufVarintWritable for u16 { - fn varint_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { - i32::varint_write_into(&(*self as i32), buf) +impl McBufVarWritable for u16 { + fn var_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + i32::var_write_into(&(*self as i32), buf) + } +} + +// Vec<T> varint +impl<T: McBufVarWritable> McBufVarWritable for Vec<T> { + fn var_write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + u32::var_write_into(&(self.len() as u32), buf)?; + for i in self { + i.var_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 f45e71c9..55fbd2e1 100644 --- a/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_add_entity_packet.rs @@ -3,11 +3,11 @@ use uuid::Uuid; #[derive(Clone, Debug, GamePacket)] pub struct ClientboundAddEntityPacket { - #[varint] + #[var] pub id: i32, pub uuid: Uuid, // TODO: have an entity type struct - #[varint] + #[var] pub entity_type: i32, pub x: f64, pub y: f64, 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 144e74c8..ab72eb59 100644 --- a/azalea-protocol/src/packets/game/clientbound_add_mob_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_add_mob_packet.rs @@ -3,11 +3,11 @@ use uuid::Uuid; #[derive(Clone, Debug, GamePacket)] pub struct ClientboundAddMobPacket { - #[varint] + #[var] pub id: i32, pub uuid: Uuid, // TODO: have an entity type struct - #[varint] + #[var] pub entity_type: i32, pub x: f64, pub y: f64, diff --git a/azalea-protocol/src/packets/game/clientbound_add_player_packet.rs b/azalea-protocol/src/packets/game/clientbound_add_player_packet.rs new file mode 100644 index 00000000..8f848c99 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_add_player_packet.rs @@ -0,0 +1,14 @@ +use packet_macros::GamePacket; +use uuid::Uuid; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundAddPlayerPacket { + #[var] + pub id: i32, + pub uuid: Uuid, + pub x: f64, + pub y: f64, + pub z: f64, + pub x_rot: i8, + pub y_rot: i8, +} diff --git a/azalea-protocol/src/packets/game/clientbound_animate_packet.rs b/azalea-protocol/src/packets/game/clientbound_animate_packet.rs new file mode 100644 index 00000000..84a20381 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_animate_packet.rs @@ -0,0 +1,20 @@ +use packet_macros::{GamePacket, McBufReadable, McBufWritable}; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundAnimatePacket { + #[var] + pub id: u32, + pub action: AnimationAction, +} + +// 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)] +pub enum AnimationAction { + SwingMainHand = 0, + Hurt = 1, + WakeUp = 2, + SwingOffHand = 3, + CriticalHit = 4, + MagicCriticalHit = 5, +} diff --git a/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs new file mode 100644 index 00000000..575b7f46 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_block_update_packet.rs @@ -0,0 +1,12 @@ +use azalea_core::BlockPos; +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundBlockUpdatePacket { + pub pos: BlockPos, + // TODO: in vanilla this is a BlockState, but here we just have it as a number. + // however, we can't add azalea-world as a dependency because it depends on us. + // we could have a crate that contains encoding/decoding and the definitions? + #[var] + pub block_state: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_chat_packet.rs b/azalea-protocol/src/packets/game/clientbound_chat_packet.rs new file mode 100644 index 00000000..3786993a --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_chat_packet.rs @@ -0,0 +1,17 @@ +use azalea_chat::component::Component; +use packet_macros::{GamePacket, McBufReadable, McBufWritable}; +use uuid::Uuid; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundChatPacket { + pub message: Component, + pub type_: ChatType, + pub sender: Uuid, +} + +#[derive(Clone, Debug, Copy, McBufReadable, McBufWritable)] +pub enum ChatType { + Chat = 0, + System = 1, + GameInfo = 2, +} 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 new file mode 100644 index 00000000..aea09e09 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_container_set_content_packet.rs @@ -0,0 +1,11 @@ +use azalea_core::Slot; +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundContainerSetContentPacket { + pub container_id: u8, + #[var] + pub state_id: u32, + pub items: Vec<Slot>, + pub carried_item: Slot, +} 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 94061c51..4fc8f86f 100644 --- a/azalea-protocol/src/packets/game/clientbound_entity_velocity_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_entity_velocity_packet.rs @@ -2,7 +2,7 @@ use packet_macros::GamePacket; #[derive(Clone, Debug, GamePacket)] pub struct ClientboundEntityVelocityPacket { - #[varint] + #[var] pub entity_id: u32, pub x_vel: i16, pub y_vel: i16, diff --git a/azalea-protocol/src/packets/game/clientbound_initialize_border_packet.rs b/azalea-protocol/src/packets/game/clientbound_initialize_border_packet.rs new file mode 100644 index 00000000..435e43cc --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_initialize_border_packet.rs @@ -0,0 +1,17 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundInitializeBorderPacket { + pub new_center_x: f64, + pub new_center_z: f64, + pub old_size: f64, + pub new_size: f64, + #[var] + pub lerp_time: u64, + #[var] + pub new_absolute_max_size: u32, + #[var] + pub warning_blocks: u32, + #[var] + pub warning_time: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_keep_alive_packet.rs b/azalea-protocol/src/packets/game/clientbound_keep_alive_packet.rs new file mode 100644 index 00000000..d5dab9a9 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_keep_alive_packet.rs @@ -0,0 +1,6 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, 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 1d4bf58c..edcb5777 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 @@ -22,7 +22,7 @@ pub struct ClientboundLevelChunkPacketData { pub struct BlockEntity { pub packed_xz: u8, pub y: u16, - #[varint] + #[var] 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 new file mode 100644 index 00000000..b8572a85 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_level_event_packet.rs @@ -0,0 +1,10 @@ +use azalea_core::BlockPos; +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundLevelEventPacket { + pub type_: i32, + pub pos: BlockPos, + pub data: i32, + pub global_event: bool, +} diff --git a/azalea-protocol/src/packets/game/clientbound_login_packet.rs b/azalea-protocol/src/packets/game/clientbound_login_packet.rs index 929b11cd..9c8b7df1 100755 --- a/azalea-protocol/src/packets/game/clientbound_login_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_login_packet.rs @@ -12,11 +12,11 @@ pub struct ClientboundLoginPacket { pub dimension_type: azalea_nbt::Tag, pub dimension: ResourceLocation, pub seed: i64, - #[varint] + #[var] pub max_players: i32, - #[varint] + #[var] pub chunk_radius: i32, - #[varint] + #[var] pub simulation_distance: i32, pub reduced_debug_info: bool, pub show_death_screen: 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 new file mode 100644 index 00000000..c9aff7cb --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_move_entity_pos_packet.rs @@ -0,0 +1,11 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundMoveEntityPosPacket { + #[var] + pub entity_id: i32, + pub xa: i16, + pub ya: i16, + pub za: i16, + 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 new file mode 100644 index 00000000..645912e7 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_move_entity_posrot_packet.rs @@ -0,0 +1,13 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundMoveEntityPosRotPacket { + #[var] + pub entity_id: i32, + pub xa: i16, + pub ya: i16, + pub za: i16, + pub y_rot: i8, + pub x_rot: i8, + pub on_ground: bool, +} 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 new file mode 100644 index 00000000..6ce0faa9 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_move_entity_rot_packet.rs @@ -0,0 +1,10 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundMoveEntityRotPacket { + #[var] + pub entity_id: i32, + pub y_rot: i8, + pub x_rot: i8, + pub on_ground: bool, +} 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 9c34d06e..8e7ce4fd 100644 --- a/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_player_info_packet.rs @@ -30,9 +30,9 @@ pub struct AddPlayer { uuid: Uuid, name: String, properties: Vec<PlayerProperty>, - #[varint] + #[var] gamemode: u32, - #[varint] + #[var] ping: i32, display_name: Option<Component>, } @@ -40,14 +40,14 @@ pub struct AddPlayer { #[derive(Clone, Debug, McBufReadable, McBufWritable)] pub struct UpdateGameMode { uuid: Uuid, - #[varint] + #[var] gamemode: u32, } #[derive(Clone, Debug, McBufReadable, McBufWritable)] pub struct UpdateLatency { uuid: Uuid, - #[varint] + #[var] ping: i32, } 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 c2bef8fa..796d8334 100644 --- a/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_player_position_packet.rs @@ -12,7 +12,7 @@ pub struct ClientboundPlayerPositionPacket { pub relative_arguments: RelativeArguments, /// Client should confirm this packet with Teleport Confirm containing the /// same Teleport ID. - #[varint] + #[var] pub id: i32, pub dismount_vehicle: bool, } diff --git a/azalea-protocol/src/packets/game/clientbound_remove_entities_packet.rs b/azalea-protocol/src/packets/game/clientbound_remove_entities_packet.rs new file mode 100644 index 00000000..265d0c64 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_remove_entities_packet.rs @@ -0,0 +1,7 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundRemoveEntitiesPacket { + #[var] + pub entity_ids: Vec<u32>, +} diff --git a/azalea-protocol/src/packets/game/clientbound_rotate_head_packet.rs b/azalea-protocol/src/packets/game/clientbound_rotate_head_packet.rs new file mode 100644 index 00000000..d423885d --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_rotate_head_packet.rs @@ -0,0 +1,8 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundRotateHeadPacket { + #[var] + pub entity_id: u32, + pub y_head_rot: i8, +} 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 5b6de0c9..60f2ab94 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 @@ -2,8 +2,8 @@ use packet_macros::GamePacket; #[derive(Clone, Debug, GamePacket)] pub struct ClientboundSetChunkCacheCenterPacket { - #[varint] + #[var] pub x: i32, - #[varint] + #[var] 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 new file mode 100644 index 00000000..dad050cc --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_default_spawn_position_packet.rs @@ -0,0 +1,8 @@ +use azalea_core::BlockPos; +use packet_macros::GamePacket; + +#[derive(Clone, Debug, 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 ca726c39..752b7e6a 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,404 +1,9 @@ -use crate::{ - mc_buf::{Readable, Writable}, - packets::{McBufReadable, McBufWritable}, -}; -use azalea_chat::component::Component; -use azalea_core::{BlockPos, Direction, Slot}; -use packet_macros::{GamePacket, McBufReadable, McBufWritable}; -use std::io::{Read, Write}; -use uuid::Uuid; +use crate::mc_buf::EntityMetadata; +use packet_macros::GamePacket; #[derive(Clone, Debug, GamePacket)] pub struct ClientboundSetEntityDataPacket { - #[varint] + #[var] pub id: i32, - pub metadata: 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, McBufReadable, McBufWritable)] -pub enum Pose { - Standing = 0, - FallFlying = 1, - Sleeping = 2, - Swimming = 3, - SpinAttack = 4, - Sneaking = 5, - LongJumping = 6, - Dying = 7, -} - -#[derive(Debug, Clone, McBufReadable, McBufWritable)] -pub struct VillagerData { - #[varint] - type_: u32, - #[varint] - profession: u32, - #[varint] - level: u32, -} - -#[derive(Debug, Clone, McBufReadable, McBufWritable)] -pub struct Particle { - #[varint] - pub id: i32, - pub data: ParticleData, -} - -#[derive(Clone, Debug)] -pub enum ParticleData { - AmbientEntityEffect, - AngryVillager, - Block(BlockParticle), - BlockMarker(BlockParticle), - Bubble, - Cloud, - Crit, - DamageIndicator, - DragonBreath, - DrippingLava, - FallingLava, - LandingLava, - DrippingWater, - FallingWater, - Dust(DustParticle), - DustColorTransition(DustColorTransitionParticle), - Effect, - ElderGuardian, - EnchantedHit, - Enchant, - EndRod, - EntityEffect, - ExplosionEmitter, - Explosion, - FallingDust(BlockParticle), - Firework, - Fishing, - Flame, - SoulFireFlame, - Soul, - Flash, - HappyVillager, - Composter, - Heart, - InstantEffect, - Item(ItemParticle), - Vibration(VibrationParticle), - ItemSlime, - ItemSnowball, - LargeSmoke, - Lava, - Mycelium, - Note, - Poof, - Portal, - Rain, - Smoke, - Sneeze, - Spit, - SquidInk, - SweepAttack, - TotemOfUndying, - Underwater, - Splash, - Witch, - BubblePop, - CurrentDown, - BubbleColumnUp, - Nautilus, - Dolphin, - CampfireCozySmoke, - CampfireSignalSmoke, - DrippingHoney, - FallingHoney, - LandingHoney, - FallingNectar, - FallingSporeBlossom, - Ash, - CrimsonSpore, - WarpedSpore, - SporeBlossomAir, - DrippingObsidianTear, - FallingObsidianTear, - LandingObsidianTear, - ReversePortal, - WhiteAsh, - SmallFlame, - Snowflake, - DrippingDripstoneLava, - FallingDripstoneLava, - DrippingDripstoneWater, - FallingDripstoneWater, - GlowSquidInk, - Glow, - WaxOn, - WaxOff, - ElectricSpark, - Scrape, -} - -#[derive(Debug, Clone, McBufReadable, McBufWritable)] -pub struct BlockParticle { - #[varint] - pub block_state: i32, -} -#[derive(Debug, Clone, McBufReadable, McBufWritable)] -pub struct DustParticle { - /// Red value, 0-1 - pub red: f32, - /// Green value, 0-1 - pub green: f32, - /// Blue value, 0-1 - pub blue: f32, - /// The scale, will be clamped between 0.01 and 4. - pub scale: f32, -} - -#[derive(Debug, Clone, McBufReadable, McBufWritable)] -pub struct DustColorTransitionParticle { - /// Red value, 0-1 - pub from_red: f32, - /// Green value, 0-1 - pub from_green: f32, - /// Blue value, 0-1 - pub from_blue: f32, - /// The scale, will be clamped between 0.01 and 4. - pub scale: f32, - /// Red value, 0-1 - pub to_red: f32, - /// Green value, 0-1 - pub to_green: f32, - /// Blue value, 0-1 - pub to_blue: f32, -} - -#[derive(Debug, Clone, McBufReadable, McBufWritable)] -pub struct ItemParticle { - pub item: Slot, -} - -#[derive(Debug, Clone, McBufReadable, McBufWritable)] -pub struct VibrationParticle { - pub origin: BlockPos, - pub position_type: String, - pub block_position: BlockPos, - #[varint] - pub entity_id: u32, - #[varint] - pub ticks: u32, -} - -impl McBufReadable for ParticleData { - fn read_into(buf: &mut impl Read) -> Result<Self, String> { - let id = buf.read_varint()?; - Ok(match id { - 0 => ParticleData::AmbientEntityEffect, - 1 => ParticleData::AngryVillager, - 2 => ParticleData::Block(BlockParticle::read_into(buf)?), - 3 => ParticleData::BlockMarker(BlockParticle::read_into(buf)?), - 4 => ParticleData::Bubble, - 5 => ParticleData::Cloud, - 6 => ParticleData::Crit, - 7 => ParticleData::DamageIndicator, - 8 => ParticleData::DragonBreath, - 9 => ParticleData::DrippingLava, - 10 => ParticleData::FallingLava, - 11 => ParticleData::LandingLava, - 12 => ParticleData::DrippingWater, - 13 => ParticleData::FallingWater, - 14 => ParticleData::Dust(DustParticle::read_into(buf)?), - 15 => ParticleData::DustColorTransition(DustColorTransitionParticle::read_into(buf)?), - 16 => ParticleData::Effect, - 17 => ParticleData::ElderGuardian, - 18 => ParticleData::EnchantedHit, - 19 => ParticleData::Enchant, - 20 => ParticleData::EndRod, - 21 => ParticleData::EntityEffect, - 22 => ParticleData::ExplosionEmitter, - 23 => ParticleData::Explosion, - 24 => ParticleData::FallingDust(BlockParticle::read_into(buf)?), - 25 => ParticleData::Firework, - 26 => ParticleData::Fishing, - 27 => ParticleData::Flame, - 28 => ParticleData::SoulFireFlame, - 29 => ParticleData::Soul, - 30 => ParticleData::Flash, - 31 => ParticleData::HappyVillager, - 32 => ParticleData::Composter, - 33 => ParticleData::Heart, - 34 => ParticleData::InstantEffect, - 35 => ParticleData::Item(ItemParticle::read_into(buf)?), - 36 => ParticleData::Vibration(VibrationParticle::read_into(buf)?), - 37 => ParticleData::ItemSlime, - 38 => ParticleData::ItemSnowball, - 39 => ParticleData::LargeSmoke, - 40 => ParticleData::Lava, - 41 => ParticleData::Mycelium, - 42 => ParticleData::Note, - 43 => ParticleData::Poof, - 44 => ParticleData::Portal, - 45 => ParticleData::Rain, - 46 => ParticleData::Smoke, - 47 => ParticleData::Sneeze, - 48 => ParticleData::Spit, - 49 => ParticleData::SquidInk, - 50 => ParticleData::SweepAttack, - 51 => ParticleData::TotemOfUndying, - 52 => ParticleData::Underwater, - 53 => ParticleData::Splash, - 54 => ParticleData::Witch, - 55 => ParticleData::BubblePop, - 56 => ParticleData::CurrentDown, - 57 => ParticleData::BubbleColumnUp, - 58 => ParticleData::Nautilus, - 59 => ParticleData::Dolphin, - 60 => ParticleData::CampfireCozySmoke, - 61 => ParticleData::CampfireSignalSmoke, - 62 => ParticleData::DrippingHoney, - 63 => ParticleData::FallingHoney, - 64 => ParticleData::LandingHoney, - 65 => ParticleData::FallingNectar, - 66 => ParticleData::FallingSporeBlossom, - 67 => ParticleData::Ash, - 68 => ParticleData::CrimsonSpore, - 69 => ParticleData::WarpedSpore, - 70 => ParticleData::SporeBlossomAir, - 71 => ParticleData::DrippingObsidianTear, - 72 => ParticleData::FallingObsidianTear, - 73 => ParticleData::LandingObsidianTear, - 74 => ParticleData::ReversePortal, - 75 => ParticleData::WhiteAsh, - 76 => ParticleData::SmallFlame, - 77 => ParticleData::Snowflake, - 78 => ParticleData::DrippingDripstoneLava, - 79 => ParticleData::FallingDripstoneLava, - 80 => ParticleData::DrippingDripstoneWater, - 81 => ParticleData::FallingDripstoneWater, - 82 => ParticleData::GlowSquidInk, - 83 => ParticleData::Glow, - 84 => ParticleData::WaxOn, - 85 => ParticleData::WaxOff, - 86 => ParticleData::ElectricSpark, - 87 => ParticleData::Scrape, - _ => return Err(format!("Unknown particle id: {}", id)), - }) - } -} - -impl McBufWritable for ParticleData { - fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> { - todo!() - } + pub metadata: EntityMetadata, } diff --git a/azalea-protocol/src/packets/game/clientbound_set_experience_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_experience_packet.rs new file mode 100644 index 00000000..88c306dc --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_experience_packet.rs @@ -0,0 +1,10 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundSetExperiencePacket { + pub experience_progress: f32, + #[var] + pub experience_level: u32, + #[var] + pub total_experience: u32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_health_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_health_packet.rs new file mode 100644 index 00000000..136ef475 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_health_packet.rs @@ -0,0 +1,9 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundSetHealthPacket { + pub health: f32, + #[var] + pub food: u32, + pub saturation: f32, +} diff --git a/azalea-protocol/src/packets/game/clientbound_set_time_packet.rs b/azalea-protocol/src/packets/game/clientbound_set_time_packet.rs new file mode 100644 index 00000000..02bf88d7 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_set_time_packet.rs @@ -0,0 +1,7 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, 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 new file mode 100644 index 00000000..67e832fe --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_sound_packet.rs @@ -0,0 +1,28 @@ +use packet_macros::{GamePacket, McBufReadable, McBufWritable}; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundSoundPacket { + #[var] + /// TODO: use the sound registry instead of just being a u32 + pub sound: u32, + pub source: SoundSource, + pub x: i32, + pub y: i32, + pub z: i32, + pub volume: f32, + pub pitch: f32, +} + +#[derive(Clone, Debug, Copy, McBufReadable, McBufWritable)] +pub enum SoundSource { + Master = 0, + Music = 1, + Records = 2, + Weather = 3, + Blocks = 4, + Hostile = 5, + Neutral = 6, + Players = 7, + Ambient = 8, + Voice = 9, +} diff --git a/azalea-protocol/src/packets/game/clientbound_teleport_entity_packet.rs b/azalea-protocol/src/packets/game/clientbound_teleport_entity_packet.rs new file mode 100644 index 00000000..ea8788d6 --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_teleport_entity_packet.rs @@ -0,0 +1,13 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundTeleportEntityPacket { + #[var] + pub id: u32, + pub x: f64, + pub y: f64, + pub z: f64, + pub y_rot: i8, + pub x_rot: i8, + pub on_ground: bool, +} diff --git a/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs new file mode 100644 index 00000000..fe2c226d --- /dev/null +++ b/azalea-protocol/src/packets/game/clientbound_update_advancements_packet.rs @@ -0,0 +1,90 @@ +use crate::packets::{McBufReadable, McBufWritable}; +use azalea_chat::component::Component; +use azalea_core::{resource_location::ResourceLocation, Slot}; +use packet_macros::{GamePacket, McBufReadable, McBufWritable}; +use std::{ + collections::HashMap, + io::{Read, Write}, +}; + +#[derive(Clone, Debug, GamePacket)] +pub struct ClientboundUpdateAdvancementsPacket { + pub reset: bool, + pub added: HashMap<ResourceLocation, Advancement>, + pub removed: Vec<ResourceLocation>, + pub progress: HashMap<ResourceLocation, AdvancementProgress>, +} + +#[derive(Clone, Debug, McBufReadable, McBufWritable)] +pub struct Advancement { + parent_id: Option<ResourceLocation>, + display: Option<DisplayInfo>, + // rewards: AdvancementRewards.EMPTY, + criteria: HashMap<ResourceLocation, Criterion>, + requirements: Vec<Vec<String>>, + // requirements_strategy: RequirementsStrategy.AND +} + +#[derive(Clone, Debug, McBufReadable, McBufWritable)] +pub struct DisplayInfo { + pub title: Component, + pub description: Component, + pub icon: Slot, + pub frame: FrameType, + pub flags: DisplayFlags, + pub background: Option<ResourceLocation>, + pub x: f32, + pub y: f32, +} + +#[derive(Clone, Debug)] +pub struct DisplayFlags { + pub background: bool, + pub show_toast: bool, + pub hidden: bool, +} + +impl McBufReadable for DisplayFlags { + fn read_into(buf: &mut impl Read) -> Result<Self, String> { + let data = u32::read_into(buf)?; + Ok(DisplayFlags { + background: (data & 0b1) != 0, + show_toast: (data & 0b10) != 0, + hidden: (data & 0b100) != 0, + }) + } +} + +impl McBufWritable for DisplayFlags { + fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { + let mut data = 0; + if self.background { + data |= 0b1; + } + if self.show_toast { + data |= 0b10; + } + if self.hidden { + data |= 0b100; + } + u32::write_into(&data, buf) + } +} + +#[derive(Clone, Debug, Copy, McBufReadable, McBufWritable)] +pub enum FrameType { + Task = 0, + Challenge = 1, + Goal = 2, +} + +// nothing is written here +#[derive(Clone, Debug, McBufReadable, McBufWritable)] +pub struct Criterion {} + +pub type AdvancementProgress = HashMap<ResourceLocation, CriterionProgress>; + +#[derive(Clone, Debug, McBufReadable, McBufWritable)] +pub struct CriterionProgress { + date: Option<u64>, +} 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 82f34f96..3d83e6fb 100644 --- a/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_update_attributes_packet.rs @@ -6,7 +6,7 @@ use uuid::Uuid; #[derive(Clone, Debug, GamePacket)] pub struct ClientboundUpdateAttributesPacket { - #[varint] + #[var] pub entity_id: u32, pub attributes: Vec<AttributeSnapshot>, } 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 9bdea26e..5b4c5cd9 100644 --- a/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs +++ b/azalea-protocol/src/packets/game/clientbound_update_recipes_packet.rs @@ -74,7 +74,7 @@ pub struct CookingRecipe { ingredient: Ingredient, result: Slot, experience: f32, - #[varint] + #[var] cooking_time: u32, } #[derive(Clone, Debug, McBufReadable, McBufWritable)] 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 1f988fe5..fe65d048 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 @@ -2,6 +2,6 @@ use packet_macros::GamePacket; #[derive(Clone, Debug, GamePacket)] pub struct ClientboundUpdateViewDistancePacket { - #[varint] + #[var] pub view_distance: i32, } diff --git a/azalea-protocol/src/packets/game/mod.rs b/azalea-protocol/src/packets/game/mod.rs index bdba6d2b..0391ee10 100755 --- a/azalea-protocol/src/packets/game/mod.rs +++ b/azalea-protocol/src/packets/game/mod.rs @@ -1,27 +1,48 @@ pub mod clientbound_add_entity_packet; pub mod clientbound_add_mob_packet; +pub mod clientbound_add_player_packet; +pub mod clientbound_animate_packet; +pub mod clientbound_block_update_packet; pub mod clientbound_change_difficulty_packet; +pub mod clientbound_chat_packet; +pub mod clientbound_container_set_content_packet; pub mod clientbound_custom_payload_packet; 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_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_light_update_packet; pub mod clientbound_login_packet; +pub mod clientbound_move_entity_pos_packet; +pub mod clientbound_move_entity_posrot_packet; +pub mod clientbound_move_entity_rot_packet; pub mod clientbound_player_abilities_packet; pub mod clientbound_player_info_packet; 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_set_carried_item_packet; pub mod clientbound_set_chunk_cache_center; +pub mod clientbound_set_default_spawn_position_packet; pub mod clientbound_set_entity_data_packet; pub mod clientbound_set_entity_link_packet; +pub mod clientbound_set_experience_packet; +pub mod clientbound_set_health_packet; +pub mod clientbound_set_time_packet; +pub mod clientbound_sound_packet; +pub mod clientbound_teleport_entity_packet; +pub mod clientbound_update_advancements_packet; pub mod clientbound_update_attributes_packet; pub mod clientbound_update_recipes_packet; pub mod clientbound_update_tags_packet; pub mod clientbound_update_view_distance_packet; pub mod serverbound_custom_payload_packet; +pub mod serverbound_keep_alive_packet; use packet_macros::declare_state_packets; @@ -29,30 +50,51 @@ declare_state_packets!( GamePacket, Serverbound => { 0x0a: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket, + 0x0f: serverbound_keep_alive_packet::ServerboundKeepAlivePacket, }, Clientbound => { 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, 0x0e: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket, + 0xf: 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, + 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, 0x25: clientbound_light_update_packet::ClientboundLightUpdatePacket, 0x26: clientbound_login_packet::ClientboundLoginPacket, + 0x29: clientbound_move_entity_pos_packet::ClientboundMoveEntityPosPacket, + 0x2a: clientbound_move_entity_posrot_packet::ClientboundMoveEntityPosRotPacket, + 0x2b: clientbound_move_entity_rot_packet::ClientboundMoveEntityRotPacket, 0x32: clientbound_player_abilities_packet::ClientboundPlayerAbilitiesPacket, 0x36: clientbound_player_info_packet::ClientboundPlayerInfoPacket, 0x38: clientbound_player_position_packet::ClientboundPlayerPositionPacket, 0x39: clientbound_recipe_packet::ClientboundRecipePacket, + 0x3a: clientbound_remove_entities_packet::ClientboundRemoveEntitiesPacket, + 0x3e: clientbound_rotate_head_packet::ClientboundRotateHeadPacket, 0x48: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket, 0x49: clientbound_set_chunk_cache_center::ClientboundSetChunkCacheCenterPacket, 0x4a: clientbound_update_view_distance_packet::ClientboundUpdateViewDistancePacket, + 0x4b: clientbound_set_default_spawn_position_packet::ClientboundSetDefaultSpawnPositionPacket, 0x4d: clientbound_set_entity_data_packet::ClientboundSetEntityDataPacket, 0x45: clientbound_set_entity_link_packet::ClientboundSetEntityLinkPacket, 0x4f: clientbound_entity_velocity_packet::ClientboundEntityVelocityPacket, + 0x51: clientbound_set_experience_packet::ClientboundSetExperiencePacket, + 0x52: clientbound_set_health_packet::ClientboundSetHealthPacket, + 0x59: clientbound_set_time_packet::ClientboundSetTimePacket, + 0x5d: clientbound_sound_packet::ClientboundSoundPacket, + 0x62: clientbound_teleport_entity_packet::ClientboundTeleportEntityPacket, + 0x63: clientbound_update_advancements_packet::ClientboundUpdateAdvancementsPacket, 0x64: clientbound_update_attributes_packet::ClientboundUpdateAttributesPacket, 0x66: clientbound_update_recipes_packet::ClientboundUpdateRecipesPacket, - 0x67: clientbound_update_tags_packet::ClientboundUpdateTagsPacket + 0x67: clientbound_update_tags_packet::ClientboundUpdateTagsPacket, } ); diff --git a/azalea-protocol/src/packets/game/serverbound_keep_alive_packet.rs b/azalea-protocol/src/packets/game/serverbound_keep_alive_packet.rs new file mode 100644 index 00000000..740b18e3 --- /dev/null +++ b/azalea-protocol/src/packets/game/serverbound_keep_alive_packet.rs @@ -0,0 +1,6 @@ +use packet_macros::GamePacket; + +#[derive(Clone, Debug, 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 6216ddc4..98caf34c 100755 --- a/azalea-protocol/src/packets/handshake/client_intention_packet.rs +++ b/azalea-protocol/src/packets/handshake/client_intention_packet.rs @@ -4,7 +4,7 @@ use std::hash::Hash; #[derive(Hash, Clone, Debug, HandshakePacket)] pub struct ClientIntentionPacket { - #[varint] + #[var] pub protocol_version: u32, pub hostname: String, pub port: u16, 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 9e1e1df5..fc5dd1a2 100755 --- a/azalea-protocol/src/packets/login/clientbound_custom_query_packet.rs +++ b/azalea-protocol/src/packets/login/clientbound_custom_query_packet.rs @@ -5,7 +5,7 @@ use std::hash::Hash; #[derive(Hash, Clone, Debug, LoginPacket)] pub struct ClientboundCustomQueryPacket { - #[varint] + #[var] pub transaction_id: u32, pub identifier: ResourceLocation, pub data: UnsizedByteArray, diff --git a/azalea-protocol/src/packets/login/clientbound_game_profile_packet.rs b/azalea-protocol/src/packets/login/clientbound_game_profile_packet.rs index dd077ced..dd11f7f7 100755 --- a/azalea-protocol/src/packets/login/clientbound_game_profile_packet.rs +++ b/azalea-protocol/src/packets/login/clientbound_game_profile_packet.rs @@ -1,6 +1,7 @@ use std::io::{Read, Write}; use super::LoginPacket; +use crate::mc_buf::McBufReadable; use crate::mc_buf::{Readable, Writable}; use azalea_auth::game_profile::GameProfile; use azalea_core::serializable_uuid::SerializableUuid; @@ -26,13 +27,7 @@ impl ClientboundGameProfilePacket { } pub fn read(buf: &mut impl Read) -> Result<LoginPacket, String> { - // TODO: we have a thing to read from the uuid now - let uuid = Uuid::from_int_array([ - buf.read_int()? as u32, - buf.read_int()? as u32, - buf.read_int()? as u32, - buf.read_int()? as u32, - ]); + let uuid = Uuid::read_into(buf)?; let name = buf.read_utf_with_len(16)?; Ok(ClientboundGameProfilePacket { game_profile: GameProfile::new(uuid, name), |
