Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Tab list header and footer customization
- Player now shows up in the tab list
- Added support for player skins
- Added boss bar (1.9+)

### Changed

Expand Down
4 changes: 2 additions & 2 deletions crates/minecraft_packets/src/login/game_profile_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use minecraft_protocol::prelude::*;
/// For versions prior to 1.20.2, this packet changes the state to Play.
#[derive(PacketOut)]
pub struct GameProfilePacket {
uuid: Uuid,
uuid: UuidAsString,
username: String,
#[pvn(759..)]
properties: LengthPaddedVec<Property>,
Expand All @@ -16,7 +16,7 @@ pub struct GameProfilePacket {
impl GameProfilePacket {
pub fn new(uuid: Uuid, username: impl ToString) -> Self {
Self {
uuid,
uuid: uuid.into(),
username: username.to_string(),
properties: LengthPaddedVec::default(),
strict_error_handling: false,
Expand Down
4 changes: 2 additions & 2 deletions crates/minecraft_packets/src/login/login_success_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use minecraft_protocol::prelude::*;
/// This packet was introduced in 1.21.2, previous versions uses the GameProfilePacket.
#[derive(PacketOut)]
pub struct LoginSuccessPacket {
uuid: Uuid,
uuid: UuidAsString,
username: String,
#[pvn(735..)]
properties: LengthPaddedVec<Property>,
Expand All @@ -13,7 +13,7 @@ pub struct LoginSuccessPacket {
impl LoginSuccessPacket {
pub fn new(uuid: Uuid, username: impl ToString) -> Self {
Self {
uuid,
uuid: uuid.into(),
username: username.to_string(),
properties: LengthPaddedVec::default(),
}
Expand Down
132 changes: 132 additions & 0 deletions crates/minecraft_packets/src/play/boss_bar_packet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use minecraft_protocol::prelude::*;
use pico_text_component::prelude::Component;

#[derive(PacketOut)]
pub struct BossBarPacket {
uuid: UuidAsLongs,
action: BossBarAction,
}

impl BossBarPacket {
pub fn add(
title: &Component,
health: f32,
color: BossBarColor,
division: BossBarDivision,
) -> Self {
let uuid = Uuid::new_v4();
Self {
uuid: uuid.into(),
action: BossBarAction::Add {
title: title.clone(),
health,
color: VarInt::from(color as i32),
division: VarInt::from(division as i32),
flags: 0,
},
}
}
}

#[allow(dead_code)]
enum BossBarAction {
Add {
title: Component,
health: f32,
color: VarInt,
division: VarInt,
/// Bit mask. 0x01: should darken sky, 0x02: is dragon bar (used to play end music), 0x04: create fog (previously was also controlled by 0x02).
flags: u8,
},
Remove,
UpdateHealth {
health: f32,
},
UpdateTitle {
title: Component,
},
UpdateStyle {
color: VarInt,
division: VarInt,
},
UpdateFlags {
flags: u8,
},
}

#[derive(Debug, Clone, Copy)]
#[repr(i32)]
pub enum BossBarColor {
Pink = 0,
Blue = 1,
Red = 2,
Green = 3,
Yellow = 4,
Purple = 5,
White = 6,
}

#[derive(Debug, Clone, Copy)]
#[repr(i32)]
pub enum BossBarDivision {
NoDivision = 0,
SixNotches = 1,
TenNotches = 2,
TwelveNotches = 3,
TwentyNotches = 4,
}

impl BossBarAction {
fn type_id(&self) -> VarInt {
match self {
Self::Add { .. } => 0.into(),
Self::Remove => 1.into(),
Self::UpdateHealth { .. } => 2.into(),
Self::UpdateTitle { .. } => 3.into(),
Self::UpdateStyle { .. } => 4.into(),
Self::UpdateFlags { .. } => 5.into(),
}
}
}

impl EncodePacket for BossBarAction {
fn encode(
&self,
writer: &mut BinaryWriter,
protocol_version: ProtocolVersion,
) -> Result<(), BinaryWriterError> {
self.type_id().encode(writer, protocol_version)?;
match self {
Self::Add {
title,
health,
color,
division,
flags,
} => {
title.encode(writer, protocol_version)?;
health.encode(writer, protocol_version)?;
color.encode(writer, protocol_version)?;
division.encode(writer, protocol_version)?;
flags.encode(writer, protocol_version)?;
}
Self::Remove => {
// Nothing to encode
}
Self::UpdateHealth { health } => {
health.encode(writer, protocol_version)?;
}
Self::UpdateTitle { title } => {
title.encode(writer, protocol_version)?;
}
Self::UpdateStyle { color, division } => {
color.encode(writer, protocol_version)?;
division.encode(writer, protocol_version)?;
}
Self::UpdateFlags { flags } => {
flags.encode(writer, protocol_version)?;
}
}
Ok(())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ pub struct LegacyChatMessagePacket {
position: u8,
/// Used by the Notchian client for the disableChat launch option. Setting both longs to 0 will always display the message regardless of the setting.
#[pvn(735..)]
sender: Uuid,
sender: UuidAsString,
}

impl LegacyChatMessagePacket {
pub fn component(component: &Component) -> Self {
Self {
content: component.to_json(),
position: 1,
sender: Uuid::nil(),
sender: UuidAsString::default(),
}
}
}
1 change: 1 addition & 0 deletions crates/minecraft_packets/src/play/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod boss_bar_packet;
pub mod chunk_data_and_update_light_packet;
pub mod client_bound_keep_alive_packet;
pub mod commands_packet;
Expand Down
13 changes: 2 additions & 11 deletions crates/minecraft_packets/src/play/player_info_update_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,8 @@ impl PlayerInfoUpdatePacket {
mask |= action.get_mask();
}

let (most_sig, least_sig) = uuid.as_u64_pair();

let player_action = Player {
v1_16_uuid: uuid,
uuid_most_sig: most_sig,
uuid_least_sig: least_sig,
uuid: uuid.into(),
action: add_player_action,
actions,
};
Expand All @@ -54,12 +50,7 @@ impl PlayerInfoUpdatePacket {

#[derive(PacketOut)]
struct Player {
#[pvn(735..)]
v1_16_uuid: Uuid,
#[pvn(..735)]
uuid_most_sig: u64,
#[pvn(..735)]
uuid_least_sig: u64,
uuid: UuidAsLongs,
#[pvn(..761)]
action: AddPlayer,
#[pvn(761..)]
Expand Down
66 changes: 62 additions & 4 deletions crates/minecraft_protocol/src/data_types/uuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,88 @@ impl DecodePacket for Uuid {
}
}

impl EncodePacket for Uuid {
/// A UUID wrapper that encodes as a string representation based on protocol version.
///
/// - Before 1.7.6: Encoded as a string without dashes (e.g., "550e8400e29b41d4a716446655440000")
/// - 1.7.6 to 1.15: Encoded as a string with dashes (e.g., "550e8400-e29b-41d4-a716-446655440000")
/// - 1.16+: Encoded as raw 16-byte array
#[derive(Default)]
pub struct UuidAsString(Uuid);

impl UuidAsString {
pub fn new(uuid: Uuid) -> Self {
Self(uuid)
}
}

impl From<Uuid> for UuidAsString {
fn from(uuid: Uuid) -> Self {
Self(uuid)
}
}

impl EncodePacket for UuidAsString {
fn encode(
&self,
writer: &mut BinaryWriter,
protocol_version: ProtocolVersion,
) -> Result<(), BinaryWriterError> {
if protocol_version.is_after_inclusive(ProtocolVersion::V1_16) {
// Since 1.16 (inclusive), UUIDs are sent as bytes
let uuid_bytes = self.as_bytes().as_slice();
let uuid_bytes = self.0.as_bytes().as_slice();
writer.write_bytes(uuid_bytes)?;
Ok(())
} else if protocol_version.is_after_inclusive(ProtocolVersion::V1_7_6) {
// Since 1.7.6 (inclusive), UUIDs are sent as strings separated by dashes
let string = VarIntPrefixedString::string(self);
let string = VarIntPrefixedString::string(self.0);
writer.write(&string)
} else {
// Before 1.7.6 (exclusive), UUIDs are sent as strings without the dashes
let string = self.to_string().replace("-", "");
let string = self.0.to_string().replace("-", "");
let protocol_string = VarIntPrefixedString::string(string);
writer.write(&protocol_string)
}
}
}

/// A UUID wrapper that encodes as either raw bytes or a pair of 64-bit integers.
///
/// - Before 1.16: Encoded as two i64 values (most significant bits, least significant bits)
/// - 1.16+: Encoded as raw 16-byte array
pub struct UuidAsLongs(Uuid);

impl UuidAsLongs {
pub fn new(uuid: Uuid) -> Self {
Self(uuid)
}
}

impl From<Uuid> for UuidAsLongs {
fn from(uuid: Uuid) -> Self {
Self(uuid)
}
}

impl EncodePacket for UuidAsLongs {
fn encode(
&self,
writer: &mut BinaryWriter,
protocol_version: ProtocolVersion,
) -> Result<(), BinaryWriterError> {
if protocol_version.is_after_inclusive(ProtocolVersion::V1_16) {
// Since 1.16 (inclusive), UUIDs are sent as bytes
let uuid_bytes = self.0.as_bytes().as_slice();
writer.write_bytes(uuid_bytes)?;
Ok(())
} else {
// Before 1.16, this Uuid variant is encoded as a pair of long
let (most_sig, least_sig) = self.0.as_u64_pair();
writer.write(&most_sig)?;
writer.write(&least_sig)
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
1 change: 1 addition & 0 deletions crates/minecraft_protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod prelude {
pub use crate::data_types::optional::{Omitted, Optional};
pub use crate::data_types::position::Position;
pub use crate::data_types::prefixed::LengthPaddedVec;
pub use crate::data_types::uuid::{UuidAsLongs, UuidAsString};
pub use crate::packet_serializer::decode_packet::DecodePacket;
pub use crate::packet_serializer::encode_packet::EncodePacket;
pub use crate::packet_serializer::packet_id::Identifiable;
Expand Down
3 changes: 3 additions & 0 deletions data/generated/V1_10/reports/packets.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
},
"minecraft:player_info_update": {
"protocol_id": 45
},
"minecraft:boss_event": {
"protocol_id": 12
}
},
"serverbound": {
Expand Down
3 changes: 3 additions & 0 deletions data/generated/V1_11/reports/packets.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
},
"minecraft:player_info_update": {
"protocol_id": 45
},
"minecraft:boss_event": {
"protocol_id": 12
}
},
"serverbound": {
Expand Down
3 changes: 3 additions & 0 deletions data/generated/V1_12/reports/packets.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
},
"minecraft:player_info_update": {
"protocol_id": 45
},
"minecraft:boss_event": {
"protocol_id": 12
}
},
"serverbound": {
Expand Down
3 changes: 3 additions & 0 deletions data/generated/V1_12_1/reports/packets.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
},
"minecraft:player_info_update": {
"protocol_id": 46
},
"minecraft:boss_event": {
"protocol_id": 12
}
},
"serverbound": {
Expand Down
3 changes: 3 additions & 0 deletions data/generated/V1_13/reports/packets.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
},
"minecraft:set_entity_data": {
"protocol_id": 63
},
"minecraft:boss_event": {
"protocol_id": 12
}
},
"serverbound": {
Expand Down
3 changes: 3 additions & 0 deletions data/generated/V1_14/reports/packets.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
},
"minecraft:set_entity_data": {
"protocol_id": 67
},
"minecraft:boss_event": {
"protocol_id": 12
}
},
"serverbound": {
Expand Down
3 changes: 3 additions & 0 deletions data/generated/V1_15/reports/packets.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
},
"minecraft:set_entity_data": {
"protocol_id": 68
},
"minecraft:boss_event": {
"protocol_id": 13
}
},
"serverbound": {
Expand Down
Loading