Skip to content

Commit 454b8b1

Browse files
AxenoDevQuozul
authored andcommitted
feat: Add support for title and action bar messages
1 parent f7fed31 commit 454b8b1

File tree

43 files changed

+771
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+771
-4
lines changed

crates/minecraft_packets/src/play/legacy_chat_message_packet.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,19 @@ pub struct LegacyChatMessagePacket {
1919
}
2020

2121
impl LegacyChatMessagePacket {
22-
pub fn component(component: &Component) -> Self {
22+
pub fn system(component: &Component) -> Self {
2323
Self {
2424
content: component.to_json(),
2525
position: 1,
2626
sender: UuidAsString::default(),
2727
}
2828
}
29+
30+
pub fn game_info(component: &Component) -> Self {
31+
Self {
32+
content: component.to_legacy(),
33+
position: 2,
34+
sender: UuidAsString::default(),
35+
}
36+
}
2937
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
use minecraft_protocol::prelude::*;
2+
use pico_text_component::prelude::Component;
3+
4+
#[derive(PacketOut)]
5+
pub struct LegacySetTitlePacket {
6+
action: LegacySetTitleAction,
7+
}
8+
9+
impl LegacySetTitlePacket {
10+
pub fn action_bar(action_bar: &Component) -> Self {
11+
Self {
12+
action: LegacySetTitleAction::SetActionBar {
13+
action_bar: action_bar.clone(),
14+
},
15+
}
16+
}
17+
18+
pub fn set_title(title: &Component) -> Self {
19+
Self {
20+
action: LegacySetTitleAction::SetTitle {
21+
title: title.clone(),
22+
},
23+
}
24+
}
25+
26+
pub fn set_subtitle(subtitle: &Component) -> Self {
27+
Self {
28+
action: LegacySetTitleAction::SetSubtitle {
29+
subtitle: subtitle.clone(),
30+
},
31+
}
32+
}
33+
34+
pub fn set_animation(fade_in: i32, stay: i32, fade_out: i32) -> Self {
35+
Self {
36+
action: LegacySetTitleAction::SetTimesAndDisplay {
37+
fade_in,
38+
stay,
39+
fade_out,
40+
},
41+
}
42+
}
43+
}
44+
45+
#[allow(dead_code)]
46+
enum LegacySetTitleAction {
47+
SetTitle {
48+
title: Component,
49+
},
50+
SetSubtitle {
51+
subtitle: Component,
52+
},
53+
SetActionBar {
54+
action_bar: Component,
55+
},
56+
SetTimesAndDisplay {
57+
fade_in: i32,
58+
stay: i32,
59+
fade_out: i32,
60+
},
61+
Hide,
62+
Reset,
63+
}
64+
65+
impl LegacySetTitleAction {
66+
fn type_id(&self, protocol_version: ProtocolVersion) -> Result<i32, BinaryWriterError> {
67+
if protocol_version.is_after_inclusive(ProtocolVersion::V1_11) {
68+
let type_id = match self {
69+
LegacySetTitleAction::SetTitle { .. } => 0,
70+
LegacySetTitleAction::SetSubtitle { .. } => 1,
71+
LegacySetTitleAction::SetActionBar { .. } => 2,
72+
LegacySetTitleAction::SetTimesAndDisplay { .. } => 3,
73+
LegacySetTitleAction::Hide => 4,
74+
LegacySetTitleAction::Reset => 5,
75+
};
76+
Ok(type_id)
77+
} else {
78+
match self {
79+
LegacySetTitleAction::SetTitle { .. } => Ok(0),
80+
LegacySetTitleAction::SetSubtitle { .. } => Ok(1),
81+
LegacySetTitleAction::SetTimesAndDisplay { .. } => Ok(2),
82+
LegacySetTitleAction::Hide => Ok(3),
83+
LegacySetTitleAction::Reset => Ok(4),
84+
LegacySetTitleAction::SetActionBar { .. } => {
85+
Err(BinaryWriterError::UnsupportedOperation)
86+
}
87+
}
88+
}
89+
}
90+
}
91+
92+
impl EncodePacket for LegacySetTitleAction {
93+
fn encode(
94+
&self,
95+
writer: &mut BinaryWriter,
96+
protocol_version: ProtocolVersion,
97+
) -> Result<(), BinaryWriterError> {
98+
let type_id = VarInt::new(self.type_id(protocol_version)?);
99+
type_id.encode(writer, protocol_version)?;
100+
match self {
101+
LegacySetTitleAction::SetTitle { title } => {
102+
title.encode(writer, protocol_version)?;
103+
}
104+
LegacySetTitleAction::SetSubtitle { subtitle } => {
105+
subtitle.encode(writer, protocol_version)?;
106+
}
107+
LegacySetTitleAction::SetActionBar { action_bar } => {
108+
if protocol_version.is_before_inclusive(ProtocolVersion::V1_10) {
109+
Err(BinaryWriterError::UnsupportedOperation)?;
110+
}
111+
action_bar.encode(writer, protocol_version)?;
112+
}
113+
LegacySetTitleAction::SetTimesAndDisplay {
114+
fade_in,
115+
stay,
116+
fade_out,
117+
} => {
118+
fade_in.encode(writer, protocol_version)?;
119+
stay.encode(writer, protocol_version)?;
120+
fade_out.encode(writer, protocol_version)?;
121+
}
122+
LegacySetTitleAction::Hide | LegacySetTitleAction::Reset => {
123+
// Nothing to encode
124+
}
125+
}
126+
Ok(())
127+
}
128+
}

crates/minecraft_packets/src/play/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@ mod data;
66
pub mod disconnect_packet;
77
pub mod game_event_packet;
88
pub mod legacy_chat_message_packet;
9+
pub mod legacy_set_title_packet;
910
pub mod login_packet;
1011
pub mod play_client_bound_plugin_message_packet;
1112
pub mod player_info_update_packet;
1213
pub mod player_position_packet;
14+
pub mod set_action_bar_text_packet;
1315
pub mod set_chunk_cache_center_packet;
1416
pub mod set_default_spawn_position_packet;
1517
pub mod set_entity_data_packet;
1618
pub mod set_player_position_and_rotation_packet;
1719
pub mod set_player_position_packet;
20+
pub mod set_subtitle_text_packet;
21+
pub mod set_title_text_packet;
22+
pub mod set_titles_animation;
1823
pub mod synchronize_player_position_packet;
1924
pub mod system_chat_message_packet;
2025
pub mod tab_list_packet;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use minecraft_protocol::prelude::*;
2+
use pico_text_component::prelude::Component;
3+
4+
#[derive(PacketOut)]
5+
pub struct SetActionBarTextPacket {
6+
text: Component,
7+
}
8+
9+
impl SetActionBarTextPacket {
10+
pub fn new(text: &Component) -> Self {
11+
Self { text: text.clone() }
12+
}
13+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use minecraft_protocol::prelude::*;
2+
use pico_text_component::prelude::Component;
3+
4+
#[derive(PacketOut)]
5+
pub struct SetSubtitleTextPacket {
6+
subtitle: Component,
7+
}
8+
9+
impl SetSubtitleTextPacket {
10+
pub fn new(subtitle: &Component) -> Self {
11+
Self {
12+
subtitle: subtitle.clone(),
13+
}
14+
}
15+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use minecraft_protocol::prelude::*;
2+
use pico_text_component::prelude::Component;
3+
4+
#[derive(PacketOut)]
5+
pub struct SetTitleTextPacket {
6+
text: Component,
7+
}
8+
9+
impl SetTitleTextPacket {
10+
pub fn new(text: &Component) -> Self {
11+
Self { text: text.clone() }
12+
}
13+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use minecraft_protocol::prelude::*;
2+
3+
#[derive(PacketOut)]
4+
pub struct SetTitlesAnimationPacket {
5+
fade_in: i32,
6+
stay: i32,
7+
fade_out: i32,
8+
}
9+
10+
impl SetTitlesAnimationPacket {
11+
pub fn new(fade_in: i32, stay: i32, fade_out: i32) -> Self {
12+
Self {
13+
fade_in,
14+
stay,
15+
fade_out,
16+
}
17+
}
18+
}

crates/pico_binutils/src/binary_writer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ pub enum BinaryWriterError {
1515
Io(#[from] std::io::Error),
1616
#[error(transparent)]
1717
TryFromInt(#[from] TryFromIntError),
18+
#[error("This operation is unsupported")]
19+
UnsupportedOperation,
1820
}
1921

2022
impl BinaryWriter {

crates/pico_text_component/src/component.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,80 @@ impl Component {
8585

8686
Nbt::compound("", compound)
8787
}
88+
89+
pub fn to_legacy(&self) -> String {
90+
#[derive(Serialize)]
91+
struct TextComponent {
92+
#[serde(default)]
93+
text: String,
94+
}
95+
serde_json::to_string(&TextComponent {
96+
text: self.to_legacy_impl(true),
97+
})
98+
.unwrap_or_default()
99+
}
100+
101+
fn to_legacy_impl(&self, is_root: bool) -> String {
102+
let mut s = String::new();
103+
104+
if !is_root {
105+
s.push('§');
106+
s.push('r');
107+
}
108+
109+
if let Some(color) = &self.color {
110+
let color_letter = match color.as_str() {
111+
"black" => '0',
112+
"dark_blue" => '1',
113+
"dark_green" => '2',
114+
"dark_aqua" => '3',
115+
"dark_red" => '4',
116+
"dark_purple" => '5',
117+
"gold" => '6',
118+
"gray" => '7',
119+
"dark_gray" => '8',
120+
"blue" => '9',
121+
"green" => 'a',
122+
"aqua" => 'b',
123+
"red" => 'c',
124+
"light_purple" => 'd',
125+
"yellow" => 'e',
126+
"white" => 'f',
127+
_ => 'f',
128+
};
129+
s.push('§');
130+
s.push(color_letter);
131+
}
132+
133+
if self.bold {
134+
s.push('§');
135+
s.push('l');
136+
}
137+
if self.italic {
138+
s.push('§');
139+
s.push('o');
140+
}
141+
if self.underlined {
142+
s.push('§');
143+
s.push('n');
144+
}
145+
if self.strikethrough {
146+
s.push('§');
147+
s.push('m');
148+
}
149+
if self.obfuscated {
150+
s.push('§');
151+
s.push('k');
152+
}
153+
154+
s.push_str(&self.text);
155+
156+
for extra in &self.extra {
157+
s.push_str(&extra.to_legacy_impl(false));
158+
}
159+
160+
s
161+
}
88162
}
89163

90164
impl EncodePacket for Component {

data/generated/V1_10/reports/packets.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@
6464
},
6565
"minecraft:boss_event": {
6666
"protocol_id": 12
67+
},
68+
"minecraft:legacy_set_title": {
69+
"protocol_id": 69
6770
}
6871
},
6972
"serverbound": {

0 commit comments

Comments
 (0)