Skip to content

Commit e7e2d40

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

File tree

40 files changed

+838
-4
lines changed

40 files changed

+838
-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: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
use minecraft_protocol::prelude::*;
2+
use pico_text_component::prelude::Component;
3+
4+
#[derive(PacketOut)]
5+
pub struct LegacySetTitlePacket {
6+
#[pvn(315..)]
7+
v1_11_action: LegacySetTitleActionWithActionBar,
8+
#[pvn(..315)]
9+
action: LegacySetTitleAction,
10+
}
11+
12+
impl LegacySetTitlePacket {
13+
pub fn create_title(
14+
title: &Component,
15+
subtitle: &Component,
16+
fade_in: i32,
17+
stay: i32,
18+
fade_out: i32,
19+
) -> Vec<Self> {
20+
vec![
21+
Self::set_title(title),
22+
Self::set_subtitle(subtitle),
23+
Self::set_animation(fade_in, stay, fade_out),
24+
]
25+
}
26+
27+
pub fn action_bar(action_bar: &Component) -> Self {
28+
Self {
29+
v1_11_action: LegacySetTitleActionWithActionBar::SetActionBar {
30+
action_bar: action_bar.clone(),
31+
},
32+
action: LegacySetTitleAction::Hide,
33+
}
34+
}
35+
36+
fn set_title(title: &Component) -> Self {
37+
Self {
38+
v1_11_action: LegacySetTitleActionWithActionBar::SetTitle {
39+
title: title.clone(),
40+
},
41+
action: LegacySetTitleAction::SetTitle {
42+
title: title.clone(),
43+
},
44+
}
45+
}
46+
47+
fn set_subtitle(subtitle: &Component) -> Self {
48+
Self {
49+
v1_11_action: LegacySetTitleActionWithActionBar::SetSubtitle {
50+
subtitle: subtitle.clone(),
51+
},
52+
action: LegacySetTitleAction::SetSubtitle {
53+
subtitle: subtitle.clone(),
54+
},
55+
}
56+
}
57+
58+
fn set_animation(fade_in: i32, stay: i32, fade_out: i32) -> Self {
59+
Self {
60+
v1_11_action: LegacySetTitleActionWithActionBar::SetTimesAndDisplay {
61+
fade_in,
62+
stay,
63+
fade_out,
64+
},
65+
action: LegacySetTitleAction::SetTimesAndDisplay {
66+
fade_in,
67+
stay,
68+
fade_out,
69+
},
70+
}
71+
}
72+
}
73+
74+
#[allow(dead_code)]
75+
enum LegacySetTitleActionWithActionBar {
76+
SetTitle {
77+
title: Component,
78+
},
79+
SetSubtitle {
80+
subtitle: Component,
81+
},
82+
SetActionBar {
83+
action_bar: Component,
84+
},
85+
SetTimesAndDisplay {
86+
fade_in: i32,
87+
stay: i32,
88+
fade_out: i32,
89+
},
90+
Hide,
91+
Reset,
92+
}
93+
94+
impl LegacySetTitleActionWithActionBar {
95+
fn type_id(&self) -> u8 {
96+
match self {
97+
LegacySetTitleActionWithActionBar::SetTitle { .. } => 0,
98+
LegacySetTitleActionWithActionBar::SetSubtitle { .. } => 1,
99+
LegacySetTitleActionWithActionBar::SetActionBar { .. } => 2,
100+
LegacySetTitleActionWithActionBar::SetTimesAndDisplay { .. } => 3,
101+
LegacySetTitleActionWithActionBar::Hide => 4,
102+
LegacySetTitleActionWithActionBar::Reset => 5,
103+
}
104+
}
105+
}
106+
107+
impl EncodePacket for LegacySetTitleActionWithActionBar {
108+
fn encode(
109+
&self,
110+
writer: &mut BinaryWriter,
111+
protocol_version: ProtocolVersion,
112+
) -> Result<(), BinaryWriterError> {
113+
self.type_id().encode(writer, protocol_version)?;
114+
match self {
115+
LegacySetTitleActionWithActionBar::SetTitle { title } => {
116+
title.encode(writer, protocol_version)?;
117+
}
118+
LegacySetTitleActionWithActionBar::SetSubtitle { subtitle } => {
119+
subtitle.encode(writer, protocol_version)?;
120+
}
121+
LegacySetTitleActionWithActionBar::SetActionBar { action_bar } => {
122+
action_bar.encode(writer, protocol_version)?;
123+
}
124+
LegacySetTitleActionWithActionBar::SetTimesAndDisplay {
125+
fade_in,
126+
stay,
127+
fade_out,
128+
} => {
129+
fade_in.encode(writer, protocol_version)?;
130+
stay.encode(writer, protocol_version)?;
131+
fade_out.encode(writer, protocol_version)?;
132+
}
133+
LegacySetTitleActionWithActionBar::Hide | LegacySetTitleActionWithActionBar::Reset => {
134+
// Nothing to encode
135+
}
136+
}
137+
Ok(())
138+
}
139+
}
140+
141+
#[allow(dead_code)]
142+
enum LegacySetTitleAction {
143+
SetTitle {
144+
title: Component,
145+
},
146+
SetSubtitle {
147+
subtitle: Component,
148+
},
149+
SetTimesAndDisplay {
150+
fade_in: i32,
151+
stay: i32,
152+
fade_out: i32,
153+
},
154+
Hide,
155+
Reset,
156+
}
157+
158+
impl LegacySetTitleAction {
159+
fn type_id(&self) -> u8 {
160+
match self {
161+
LegacySetTitleAction::SetTitle { .. } => 0,
162+
LegacySetTitleAction::SetSubtitle { .. } => 1,
163+
LegacySetTitleAction::SetTimesAndDisplay { .. } => 2,
164+
LegacySetTitleAction::Hide => 3,
165+
LegacySetTitleAction::Reset => 4,
166+
}
167+
}
168+
}
169+
170+
impl EncodePacket for LegacySetTitleAction {
171+
fn encode(
172+
&self,
173+
writer: &mut BinaryWriter,
174+
protocol_version: ProtocolVersion,
175+
) -> Result<(), BinaryWriterError> {
176+
self.type_id().encode(writer, protocol_version)?;
177+
match self {
178+
LegacySetTitleAction::SetTitle { title } => {
179+
title.encode(writer, protocol_version)?;
180+
}
181+
LegacySetTitleAction::SetSubtitle { subtitle } => {
182+
subtitle.encode(writer, protocol_version)?;
183+
}
184+
LegacySetTitleAction::SetTimesAndDisplay {
185+
fade_in,
186+
stay,
187+
fade_out,
188+
} => {
189+
fade_in.encode(writer, protocol_version)?;
190+
stay.encode(writer, protocol_version)?;
191+
fade_out.encode(writer, protocol_version)?;
192+
}
193+
LegacySetTitleAction::Hide | LegacySetTitleAction::Reset => {
194+
// Nothing to encode
195+
}
196+
}
197+
Ok(())
198+
}
199+
}

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_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)