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