chunkedge_protocol/packets/play/
player_info_update_s2c.rs

1use std::borrow::Cow;
2use std::io::Write;
3
4use bitfield_struct::bitfield;
5use chunkedge_binary::{Decode, Encode, TextComponent, VarInt};
6use uuid::Uuid;
7
8use crate::profile::Property;
9use crate::{GameMode, Packet};
10
11#[derive(Clone, Debug, Packet)]
12pub struct PlayerInfoUpdateS2c<'a> {
13    pub actions: PlayerListActions,
14    pub entries: Cow<'a, [PlayerListEntry<'a>]>,
15}
16
17#[bitfield(u8)]
18pub struct PlayerListActions {
19    pub add_player: bool,
20    pub initialize_chat: bool,
21    pub update_game_mode: bool,
22    pub update_listed: bool,
23    pub update_latency: bool,
24    pub update_display_name: bool,
25    pub update_priority: bool,
26    pub update_hat: bool,
27}
28
29#[derive(Clone, Default, Debug)]
30pub struct PlayerListEntry<'a> {
31    pub player_uuid: Uuid,
32    pub username: &'a str,
33    pub properties: Cow<'a, [Property]>,
34    pub chat_data: Option<ChatData<'a>>,
35    pub listed: bool,
36    pub ping: i32,
37    pub game_mode: GameMode,
38    pub display_name: Option<Cow<'a, TextComponent>>,
39    pub priority: i32,
40    pub hat: bool,
41}
42
43#[derive(Clone, PartialEq, Debug, Encode, Decode)]
44pub struct ChatData<'a> {
45    pub session_id: Uuid,
46    /// Unix timestamp in milliseconds.
47    pub key_expiry_time: i64,
48    pub public_key: &'a [u8],
49    pub public_key_signature: &'a [u8],
50}
51
52impl Encode for PlayerInfoUpdateS2c<'_> {
53    fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
54        self.actions.0.encode(&mut w)?;
55
56        // Write number of entries.
57        VarInt(self.entries.len() as i32).encode(&mut w)?;
58
59        for entry in self.entries.as_ref() {
60            entry.player_uuid.encode(&mut w)?;
61
62            if self.actions.add_player() {
63                entry.username.encode(&mut w)?;
64                entry.properties.encode(&mut w)?;
65            }
66
67            if self.actions.initialize_chat() {
68                entry.chat_data.encode(&mut w)?;
69            }
70
71            if self.actions.update_game_mode() {
72                entry.game_mode.encode(&mut w)?;
73            }
74
75            if self.actions.update_listed() {
76                entry.listed.encode(&mut w)?;
77            }
78
79            if self.actions.update_latency() {
80                VarInt(entry.ping).encode(&mut w)?;
81            }
82
83            if self.actions.update_display_name() {
84                entry.display_name.encode(&mut w)?;
85            }
86
87            if self.actions.update_priority() {
88                VarInt(entry.priority).encode(&mut w)?;
89            }
90
91            if self.actions.update_hat() {
92                entry.hat.encode(&mut w)?;
93            }
94        }
95
96        Ok(())
97    }
98}
99
100impl<'a> Decode<'a> for PlayerInfoUpdateS2c<'a> {
101    fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
102        let actions = PlayerListActions(u8::decode(r)?);
103
104        let mut entries = vec![];
105
106        for _ in 0..VarInt::decode(r)?.0 {
107            let mut entry = PlayerListEntry {
108                player_uuid: Uuid::decode(r)?,
109                ..Default::default()
110            };
111
112            if actions.add_player() {
113                entry.username = Decode::decode(r)?;
114                entry.properties = Decode::decode(r)?;
115            }
116
117            if actions.initialize_chat() {
118                entry.chat_data = Decode::decode(r)?;
119            }
120
121            if actions.update_game_mode() {
122                entry.game_mode = Decode::decode(r)?;
123            }
124
125            if actions.update_listed() {
126                entry.listed = Decode::decode(r)?;
127            }
128
129            if actions.update_latency() {
130                entry.ping = VarInt::decode(r)?.0;
131            }
132
133            if actions.update_display_name() {
134                entry.display_name = Decode::decode(r)?;
135            }
136
137            if actions.update_priority() {
138                entry.priority = VarInt::decode(r)?.0;
139            }
140
141            if actions.update_hat() {
142                entry.hat = bool::decode(r)?;
143            }
144
145            entries.push(entry);
146        }
147
148        Ok(Self {
149            actions,
150            entries: entries.into(),
151        })
152    }
153}