1use std::{
2 collections::HashMap,
3 io::{Cursor, Write},
4};
5
6use azalea_auth::game_profile::{GameProfile, ProfilePropertyValue};
7use azalea_buf::{AzBuf, AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
8use azalea_chat::FormattedText;
9use azalea_core::{bitset::FixedBitSet, game_type::GameMode};
10use azalea_protocol_macros::ClientboundGamePacket;
11use uuid::Uuid;
12
13use super::s_chat_session_update::RemoteChatSessionData;
14
15#[derive(Clone, Debug, ClientboundGamePacket)]
16pub struct ClientboundPlayerInfoUpdate {
17 pub actions: ActionEnumSet,
18 pub entries: Vec<PlayerInfoEntry>,
19}
20
21#[derive(Clone, Debug, Default)]
22pub struct PlayerInfoEntry {
23 pub profile: GameProfile,
24 pub listed: bool,
25 pub latency: i32,
26 pub game_mode: GameMode,
27 pub display_name: Option<FormattedText>,
28 pub list_order: i32,
29 pub update_hat: bool,
30 pub chat_session: Option<RemoteChatSessionData>,
31}
32
33#[derive(Clone, Debug, AzBuf)]
34pub struct AddPlayerAction {
35 pub name: String,
36 pub properties: HashMap<String, ProfilePropertyValue>,
37}
38#[derive(Clone, Debug, AzBuf)]
39pub struct InitializeChatAction {
40 pub chat_session: Option<RemoteChatSessionData>,
41}
42#[derive(Clone, Debug, AzBuf)]
43pub struct UpdateGameModeAction {
44 pub game_mode: GameMode,
45}
46#[derive(Clone, Debug, AzBuf)]
47pub struct UpdateListedAction {
48 pub listed: bool,
49}
50#[derive(Clone, Debug, AzBuf)]
51pub struct UpdateLatencyAction {
52 #[var]
53 pub latency: i32,
54}
55#[derive(Clone, Debug, AzBuf)]
56pub struct UpdateDisplayNameAction {
57 pub display_name: Option<FormattedText>,
58}
59#[derive(Clone, Debug, AzBuf)]
60pub struct UpdateHatAction {
61 pub update_hat: bool,
62}
63#[derive(Clone, Debug, AzBuf)]
64pub struct UpdateListOrderAction {
65 #[var]
66 pub list_order: i32,
67}
68
69impl AzaleaRead for ClientboundPlayerInfoUpdate {
70 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
71 let actions = ActionEnumSet::azalea_read(buf)?;
72 let mut entries = Vec::new();
73
74 let entry_count = u32::azalea_read_var(buf)?;
75 for _ in 0..entry_count {
76 let profile_id = Uuid::azalea_read(buf)?;
77 let mut entry = PlayerInfoEntry::default();
78 entry.profile.uuid = profile_id;
79
80 if actions.add_player {
81 let action = AddPlayerAction::azalea_read(buf)?;
82 entry.profile.name = action.name;
83 entry.profile.properties = action.properties;
84 }
85 if actions.initialize_chat {
86 let action = InitializeChatAction::azalea_read(buf)?;
87 entry.chat_session = action.chat_session;
88 }
89 if actions.update_game_mode {
90 let action = UpdateGameModeAction::azalea_read(buf)?;
91 entry.game_mode = action.game_mode;
92 }
93 if actions.update_listed {
94 let action = UpdateListedAction::azalea_read(buf)?;
95 entry.listed = action.listed;
96 }
97 if actions.update_latency {
98 let action = UpdateLatencyAction::azalea_read(buf)?;
99 entry.latency = action.latency;
100 }
101 if actions.update_display_name {
102 let action = UpdateDisplayNameAction::azalea_read(buf)?;
103 entry.display_name = action.display_name;
104 }
105 if actions.update_hat {
106 let action = UpdateHatAction::azalea_read(buf)?;
107 entry.update_hat = action.update_hat;
108 }
109 if actions.update_list_order {
110 let action = UpdateListOrderAction::azalea_read(buf)?;
111 entry.list_order = action.list_order;
112 }
113
114 entries.push(entry);
115 }
116
117 Ok(ClientboundPlayerInfoUpdate { actions, entries })
118 }
119}
120
121impl AzaleaWrite for ClientboundPlayerInfoUpdate {
122 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
123 self.actions.azalea_write(buf)?;
124
125 (self.entries.len() as u32).azalea_write_var(buf)?;
126 for entry in &self.entries {
127 entry.profile.uuid.azalea_write(buf)?;
128
129 if self.actions.add_player {
130 AddPlayerAction {
131 name: entry.profile.name.clone(),
132 properties: entry.profile.properties.clone(),
133 }
134 .azalea_write(buf)?;
135 }
136 if self.actions.initialize_chat {
137 InitializeChatAction {
138 chat_session: entry.chat_session.clone(),
139 }
140 .azalea_write(buf)?;
141 }
142 if self.actions.update_game_mode {
143 UpdateGameModeAction {
144 game_mode: entry.game_mode,
145 }
146 .azalea_write(buf)?;
147 }
148 if self.actions.update_listed {
149 UpdateListedAction {
150 listed: entry.listed,
151 }
152 .azalea_write(buf)?;
153 }
154 if self.actions.update_latency {
155 UpdateLatencyAction {
156 latency: entry.latency,
157 }
158 .azalea_write(buf)?;
159 }
160 if self.actions.update_display_name {
161 UpdateDisplayNameAction {
162 display_name: entry.display_name.clone(),
163 }
164 .azalea_write(buf)?;
165 }
166 }
167
168 Ok(())
169 }
170}
171
172#[derive(Clone, Debug, PartialEq, Eq)]
173pub struct ActionEnumSet {
174 pub add_player: bool,
175 pub initialize_chat: bool,
176 pub update_game_mode: bool,
177 pub update_listed: bool,
178 pub update_latency: bool,
179 pub update_display_name: bool,
180 pub update_hat: bool,
181 pub update_list_order: bool,
182}
183
184impl AzaleaRead for ActionEnumSet {
185 fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
186 let set = FixedBitSet::<{ 7_usize.div_ceil(8) }>::azalea_read(buf)?;
187 Ok(ActionEnumSet {
188 add_player: set.index(0),
189 initialize_chat: set.index(1),
190 update_game_mode: set.index(2),
191 update_listed: set.index(3),
192 update_latency: set.index(4),
193 update_display_name: set.index(5),
194 update_hat: set.index(6),
195 update_list_order: set.index(7),
196 })
197 }
198}
199
200impl AzaleaWrite for ActionEnumSet {
201 fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
202 let mut set = FixedBitSet::<{ 7_usize.div_ceil(8) }>::new();
203 if self.add_player {
204 set.set(0);
205 }
206 if self.initialize_chat {
207 set.set(1);
208 }
209 if self.update_game_mode {
210 set.set(2);
211 }
212 if self.update_listed {
213 set.set(3);
214 }
215 if self.update_latency {
216 set.set(4);
217 }
218 if self.update_display_name {
219 set.set(5);
220 }
221 if self.update_hat {
222 set.set(6);
223 }
224 if self.update_list_order {
225 set.set(7);
226 }
227 set.azalea_write(buf)?;
228 Ok(())
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 #[test]
237 fn test_action_enum_set() {
238 let data = ActionEnumSet {
239 add_player: true,
240 initialize_chat: false,
241 update_game_mode: true,
242 update_listed: false,
243 update_latency: true,
244 update_display_name: false,
245 update_hat: false,
246 update_list_order: true,
247 };
248 let mut buf = Vec::new();
249 data.azalea_write(&mut buf).unwrap();
250 let mut data_cursor: Cursor<&[u8]> = Cursor::new(&buf);
251 let read_data = ActionEnumSet::azalea_read(&mut data_cursor).unwrap();
252 assert_eq!(read_data, data);
253 }
254
255 #[test]
256 fn read_player_info_update_packet() {
257 let mut bytes = Cursor::new(
259 &[
260 63, 1, 196, 217, 99, 243, 221, 101, 79, 183, 167, 88, 48, 71, 25, 49, 5, 142, 5,
261 74, 66, 76, 80, 78, 1, 8, 116, 101, 120, 116, 117, 114, 101, 115, 152, 3, 101, 119,
262 111, 103, 73, 67, 74, 48, 97, 87, 49, 108, 99, 51, 82, 104, 98, 88, 65, 105, 73,
263 68, 111, 103, 77, 84, 99, 119, 77, 106, 99, 49, 78, 106, 89, 48, 77, 68, 81, 120,
264 78, 105, 119, 75, 73, 67, 65, 105, 99, 72, 74, 118, 90, 109, 108, 115, 90, 85, 108,
265 107, 73, 105, 65, 54, 73, 67, 74, 106, 78, 71, 81, 53, 78, 106, 78, 109, 77, 50,
266 82, 107, 78, 106, 85, 48, 90, 109, 73, 51, 89, 84, 99, 49, 79, 68, 77, 119, 78, 68,
267 99, 120, 79, 84, 77, 120, 77, 68, 85, 52, 90, 83, 73, 115, 67, 105, 65, 103, 73,
268 110, 66, 121, 98, 50, 90, 112, 98, 71, 86, 79, 89, 87, 49, 108, 73, 105, 65, 54,
269 73, 67, 74, 75, 81, 107, 120, 81, 84, 105, 73, 115, 67, 105, 65, 103, 73, 110, 78,
270 112, 90, 50, 53, 104, 100, 72, 86, 121, 90, 86, 74, 108, 99, 88, 86, 112, 99, 109,
271 86, 107, 73, 105, 65, 54, 73, 72, 82, 121, 100, 87, 85, 115, 67, 105, 65, 103, 73,
272 110, 82, 108, 101, 72, 82, 49, 99, 109, 86, 122, 73, 105, 65, 54, 73, 72, 115, 75,
273 73, 67, 65, 103, 73, 67, 74, 84, 83, 48, 108, 79, 73, 105, 65, 54, 73, 72, 115, 75,
274 73, 67, 65, 103, 73, 67, 65, 103, 73, 110, 86, 121, 98, 67, 73, 103, 79, 105, 65,
275 105, 97, 72, 82, 48, 99, 68, 111, 118, 76, 51, 82, 108, 101, 72, 82, 49, 99, 109,
276 86, 122, 76, 109, 49, 112, 98, 109, 86, 106, 99, 109, 70, 109, 100, 67, 53, 117,
277 90, 88, 81, 118, 100, 71, 86, 52, 100, 72, 86, 121, 90, 83, 56, 48, 79, 68, 107,
278 120, 89, 84, 107, 50, 89, 84, 74, 107, 77, 84, 103, 120, 78, 84, 69, 49, 79, 68,
279 107, 52, 78, 68, 89, 119, 77, 68, 82, 106, 77, 106, 100, 104, 78, 50, 86, 106, 77,
280 106, 85, 53, 77, 87, 77, 120, 79, 68, 66, 108, 77, 84, 70, 109, 77, 122, 104, 107,
281 89, 122, 69, 52, 77, 84, 74, 109, 77, 106, 100, 104, 77, 71, 82, 108, 78, 50, 69,
282 120, 77, 87, 85, 120, 73, 103, 111, 103, 73, 67, 65, 103, 102, 81, 111, 103, 73,
283 72, 48, 75, 102, 81, 61, 61, 1, 172, 5, 117, 69, 67, 88, 54, 83, 104, 55, 67, 100,
284 87, 49, 77, 99, 78, 88, 122, 72, 73, 105, 90, 86, 43, 103, 111, 121, 47, 120, 53,
285 102, 51, 65, 113, 119, 50, 115, 102, 114, 104, 106, 67, 118, 67, 102, 97, 54, 67,
286 112, 55, 88, 116, 109, 103, 118, 113, 73, 114, 122, 100, 85, 72, 90, 102, 79, 100,
287 100, 112, 109, 87, 70, 110, 70, 119, 97, 85, 109, 97, 76, 106, 86, 102, 121, 88,
288 119, 115, 76, 48, 78, 108, 118, 98, 56, 78, 104, 121, 115, 113, 87, 47, 104, 75,
289 120, 101, 86, 117, 90, 68, 71, 43, 102, 54, 98, 99, 98, 81, 113, 76, 79, 54, 83,
290 66, 88, 111, 81, 74, 85, 104, 74, 66, 90, 102, 88, 78, 53, 51, 100, 102, 80, 98,
291 75, 89, 81, 54, 68, 77, 57, 87, 102, 113, 81, 76, 100, 55, 121, 117, 119, 90, 81,
292 68, 55, 120, 48, 54, 118, 102, 105, 72, 121, 48, 110, 87, 50, 99, 68, 111, 72, 101,
293 71, 102, 72, 67, 53, 104, 52, 112, 84, 109, 65, 101, 100, 101, 109, 116, 48, 67,
294 72, 113, 86, 54, 76, 67, 77, 89, 118, 101, 110, 84, 88, 68, 83, 81, 107, 82, 43,
295 50, 53, 74, 76, 120, 101, 98, 74, 105, 98, 108, 54, 88, 106, 73, 118, 88, 120, 105,
296 87, 68, 121, 85, 49, 65, 43, 121, 48, 79, 104, 53, 89, 115, 116, 121, 86, 116, 106,
297 107, 76, 113, 67, 56, 85, 57, 118, 86, 110, 87, 65, 102, 111, 43, 52, 104, 78, 43,
298 79, 51, 122, 108, 72, 117, 84, 50, 87, 76, 86, 121, 98, 43, 88, 72, 100, 67, 111,
299 111, 88, 75, 82, 75, 83, 86, 71, 101, 122, 103, 75, 78, 47, 53, 65, 53, 67, 119,
300 78, 112, 82, 87, 98, 81, 55, 109, 90, 47, 108, 51, 57, 84, 114, 100, 84, 99, 54,
301 121, 79, 88, 73, 48, 56, 83, 101, 73, 54, 68, 118, 118, 50, 55, 78, 66, 112, 107,
302 47, 97, 72, 119, 65, 49, 116, 105, 78, 108, 55, 122, 49, 103, 97, 79, 107, 113,
303 107, 116, 54, 120, 85, 116, 70, 84, 85, 122, 72, 71, 97, 107, 69, 118, 105, 76, 72,
304 120, 67, 99, 106, 98, 121, 88, 111, 76, 71, 101, 101, 50, 57, 81, 84, 73, 102, 99,
305 97, 69, 56, 104, 108, 110, 73, 97, 74, 111, 115, 72, 117, 57, 116, 100, 54, 52,
306 119, 74, 88, 74, 115, 69, 78, 114, 121, 69, 56, 70, 53, 52, 52, 116, 114, 84, 54,
307 105, 112, 122, 73, 119, 43, 118, 120, 112, 76, 121, 88, 65, 87, 116, 103, 83, 113,
308 76, 108, 107, 121, 78, 50, 77, 115, 57, 74, 89, 110, 100, 79, 111, 90, 57, 77, 53,
309 84, 49, 87, 112, 75, 70, 97, 52, 55, 114, 112, 80, 106, 75, 114, 79, 107, 114, 110,
310 100, 50, 97, 83, 51, 90, 86, 77, 120, 118, 79, 49, 111, 78, 47, 100, 84, 55, 116,
311 77, 119, 82, 52, 109, 97, 55, 85, 73, 68, 50, 48, 84, 113, 105, 83, 75, 56, 108,
312 76, 85, 100, 53, 48, 86, 119, 108, 112, 67, 116, 98, 76, 99, 71, 86, 82, 98, 78,
313 84, 97, 108, 90, 83, 66, 56, 88, 65, 72, 72, 78, 100, 116, 88, 86, 50, 49, 111, 68,
314 77, 116, 77, 122, 79, 104, 82, 109, 43, 57, 88, 81, 90, 79, 50, 55, 66, 69, 71, 65,
315 47, 119, 117, 104, 113, 71, 108, 106, 82, 111, 76, 72, 111, 102, 98, 71, 48, 52,
316 82, 55, 84, 43, 80, 99, 112, 77, 116, 65, 69, 105, 49, 100, 57, 99, 66, 90, 115,
317 119, 84, 105, 107, 113, 114, 89, 49, 86, 49, 48, 106, 104, 77, 76, 118, 99, 99, 78,
318 50, 109, 70, 43, 89, 86, 81, 101, 48, 90, 55, 43, 78, 100, 119, 119, 104, 121, 47,
319 108, 79, 72, 81, 54, 71, 108, 122, 74, 110, 87, 122, 103, 50, 107, 61, 0, 255, 255,
320 255, 255, 15, 1, 255, 255, 255, 255, 15, 1, 10, 8, 0, 4, 116, 101, 120, 116, 0, 0,
321 0,
322 ][..],
323 );
324 let _packet = ClientboundPlayerInfoUpdate::azalea_read(&mut bytes).unwrap();
325 }
326}