Skip to main content

kojacoord_protocol/versions/v1_21/login/
mod.rs

1use bytes::{Bytes, BytesMut};
2
3use crate::codec::{decode_byte_array, encode_byte_array, Decode, Encode, PacketId};
4use crate::error::ProtocolError;
5use crate::types::VarInt;
6
7#[derive(Debug, Clone, PartialEq)]
8pub struct ServerboundLoginStart {
9    pub username: String,
10    pub uuid: uuid::Uuid,
11}
12
13impl PacketId for ServerboundLoginStart {
14    fn packet_id(_ver: u32) -> u8 {
15        0x00
16    }
17}
18
19impl Encode for ServerboundLoginStart {
20    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
21        self.username.encode(dst)?;
22        self.uuid.encode(dst)
23    }
24}
25
26impl Decode for ServerboundLoginStart {
27    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
28        let username = String::decode(src)?;
29        let uuid = uuid::Uuid::decode(src)?;
30        Ok(Self { username, uuid })
31    }
32}
33
34#[derive(Debug, Clone, PartialEq)]
35pub struct ClientboundLoginDisconnect {
36    pub reason: String,
37}
38
39impl PacketId for ClientboundLoginDisconnect {
40    fn packet_id(_ver: u32) -> u8 {
41        0x00
42    }
43}
44
45impl Encode for ClientboundLoginDisconnect {
46    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
47        self.reason.encode(dst)
48    }
49}
50
51impl Decode for ClientboundLoginDisconnect {
52    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
53        Ok(Self {
54            reason: String::decode(src)?,
55        })
56    }
57}
58
59#[derive(Debug, Clone, PartialEq)]
60pub struct ClientboundEncryptionRequest {
61    pub server_id: String,
62
63    pub public_key: Vec<u8>,
64
65    pub verify_token: Vec<u8>,
66
67    pub should_authenticate: bool,
68}
69
70impl PacketId for ClientboundEncryptionRequest {
71    fn packet_id(_ver: u32) -> u8 {
72        0x01
73    }
74}
75
76impl Encode for ClientboundEncryptionRequest {
77    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
78        self.server_id.encode(dst)?;
79        encode_byte_array(&self.public_key, dst)?;
80        encode_byte_array(&self.verify_token, dst)?;
81        self.should_authenticate.encode(dst)
82    }
83}
84
85impl Decode for ClientboundEncryptionRequest {
86    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
87        let server_id = String::decode(src)?;
88        let public_key = decode_byte_array(src)?;
89        let verify_token = decode_byte_array(src)?;
90        let should_authenticate = bool::decode(src)?;
91        Ok(Self {
92            server_id,
93            public_key,
94            verify_token,
95            should_authenticate,
96        })
97    }
98}
99
100#[derive(Debug, Clone, PartialEq)]
101pub struct ProfileProperty {
102    pub name: String,
103
104    pub value: String,
105
106    pub signature: Option<String>,
107}
108
109impl Encode for ProfileProperty {
110    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
111        self.name.encode(dst)?;
112        self.value.encode(dst)?;
113        self.signature.encode(dst)
114    }
115}
116
117impl Decode for ProfileProperty {
118    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
119        let name = String::decode(src)?;
120        let value = String::decode(src)?;
121        let signature = Option::<String>::decode(src)?;
122        Ok(Self {
123            name,
124            value,
125            signature,
126        })
127    }
128}
129
130#[derive(Debug, Clone, PartialEq)]
131pub struct ClientboundLoginSuccess {
132    pub uuid: uuid::Uuid,
133
134    pub username: String,
135
136    pub properties: Vec<ProfileProperty>,
137}
138
139impl PacketId for ClientboundLoginSuccess {
140    fn packet_id(_ver: u32) -> u8 {
141        0x02
142    }
143}
144
145impl Encode for ClientboundLoginSuccess {
146    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
147        let (hi, lo) = self.uuid.as_u64_pair();
148        (hi as i64).encode(dst)?;
149        (lo as i64).encode(dst)?;
150        self.username.encode(dst)?;
151        self.properties.encode(dst)
152    }
153}
154
155impl Decode for ClientboundLoginSuccess {
156    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
157        let hi = i64::decode(src)? as u64;
158        let lo = i64::decode(src)? as u64;
159        let uuid = uuid::Uuid::from_u64_pair(hi, lo);
160        let username = String::decode(src)?;
161        let properties = Vec::<ProfileProperty>::decode(src)?;
162        Ok(Self {
163            uuid,
164            username,
165            properties,
166        })
167    }
168}
169
170#[derive(Debug, Clone, PartialEq)]
171pub struct ClientboundSetCompression {
172    pub threshold: VarInt,
173}
174
175impl PacketId for ClientboundSetCompression {
176    fn packet_id(_ver: u32) -> u8 {
177        0x03
178    }
179}
180
181impl Encode for ClientboundSetCompression {
182    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
183        self.threshold.encode(dst)
184    }
185}
186
187impl Decode for ClientboundSetCompression {
188    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
189        Ok(Self {
190            threshold: VarInt::decode(src)?,
191        })
192    }
193}
194
195#[derive(Debug, Clone, PartialEq)]
196pub struct ClientboundLoginPluginRequest {
197    pub message_id: VarInt,
198
199    pub channel: String,
200
201    pub data: Vec<u8>,
202}
203
204impl PacketId for ClientboundLoginPluginRequest {
205    fn packet_id(_ver: u32) -> u8 {
206        0x04
207    }
208}
209
210impl Encode for ClientboundLoginPluginRequest {
211    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
212        self.message_id.encode(dst)?;
213        self.channel.encode(dst)?;
214        dst.extend_from_slice(&self.data);
215        Ok(())
216    }
217}
218
219impl Decode for ClientboundLoginPluginRequest {
220    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
221        let message_id = VarInt::decode(src)?;
222        let channel = String::decode(src)?;
223        let data = src.split_to(src.len()).to_vec();
224        Ok(Self {
225            message_id,
226            channel,
227            data,
228        })
229    }
230}
231
232#[derive(Debug, Clone, PartialEq)]
233pub struct ServerboundEncryptionResponse {
234    pub shared_secret: Vec<u8>,
235
236    pub verify_token: Vec<u8>,
237}
238
239impl PacketId for ServerboundEncryptionResponse {
240    fn packet_id(_ver: u32) -> u8 {
241        0x01
242    }
243}
244
245impl Encode for ServerboundEncryptionResponse {
246    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
247        encode_byte_array(&self.shared_secret, dst)?;
248        encode_byte_array(&self.verify_token, dst)
249    }
250}
251
252impl Decode for ServerboundEncryptionResponse {
253    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
254        let shared_secret = decode_byte_array(src)?;
255        let verify_token = decode_byte_array(src)?;
256        Ok(Self {
257            shared_secret,
258            verify_token,
259        })
260    }
261}
262
263#[derive(Debug, Clone, PartialEq)]
264pub struct ServerboundLoginPluginResponse {
265    pub message_id: VarInt,
266
267    pub data: Option<Vec<u8>>,
268}
269
270impl PacketId for ServerboundLoginPluginResponse {
271    fn packet_id(_ver: u32) -> u8 {
272        0x02
273    }
274}
275
276impl Encode for ServerboundLoginPluginResponse {
277    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
278        self.message_id.encode(dst)?;
279        match &self.data {
280            Some(payload) => {
281                true.encode(dst)?;
282                dst.extend_from_slice(payload);
283            },
284            None => false.encode(dst)?,
285        }
286        Ok(())
287    }
288}
289
290impl Decode for ServerboundLoginPluginResponse {
291    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
292        let message_id = VarInt::decode(src)?;
293        let understood = bool::decode(src)?;
294        let data = if understood {
295            Some(src.split_to(src.len()).to_vec())
296        } else {
297            None
298        };
299        Ok(Self { message_id, data })
300    }
301}
302
303#[derive(Debug, Clone, PartialEq)]
304pub struct ServerboundLoginAcknowledged;
305
306impl PacketId for ServerboundLoginAcknowledged {
307    fn packet_id(_ver: u32) -> u8 {
308        0x03
309    }
310}
311
312impl Encode for ServerboundLoginAcknowledged {
313    fn encode(&self, _dst: &mut BytesMut) -> Result<(), ProtocolError> {
314        Ok(())
315    }
316}
317
318impl Decode for ServerboundLoginAcknowledged {
319    fn decode(_src: &mut Bytes) -> Result<Self, ProtocolError> {
320        Ok(Self)
321    }
322}
323
324#[cfg(test)]
325mod tests {
326    use super::*;
327
328    #[test]
329    fn login_start_roundtrip() {
330        let p = ServerboundLoginStart {
331            username: "Player1".to_string(),
332            uuid: uuid::Uuid::new_v4(),
333        };
334        let mut buf = BytesMut::new();
335        p.encode(&mut buf).unwrap();
336        let mut b = buf.freeze();
337        assert_eq!(ServerboundLoginStart::decode(&mut b).unwrap(), p);
338    }
339
340    #[test]
341    fn login_success_empty_properties() {
342        let p = ClientboundLoginSuccess {
343            uuid: uuid::Uuid::new_v4(),
344            username: "Player1".to_string(),
345            properties: Vec::new(),
346        };
347        let mut buf = BytesMut::new();
348        p.encode(&mut buf).unwrap();
349        let mut b = buf.freeze();
350        let d = ClientboundLoginSuccess::decode(&mut b).unwrap();
351        assert_eq!(d.uuid, p.uuid);
352        assert_eq!(d.username, p.username);
353        assert!(d.properties.is_empty());
354    }
355
356    #[test]
357    fn login_success_with_properties() {
358        let p = ClientboundLoginSuccess {
359            uuid: uuid::Uuid::new_v4(),
360            username: "Player1".to_string(),
361            properties: vec![
362                ProfileProperty {
363                    name: "textures".to_string(),
364                    value: "abc123".to_string(),
365                    signature: Some("sig".to_string()),
366                },
367                ProfileProperty {
368                    name: "other".to_string(),
369                    value: "val".to_string(),
370                    signature: None,
371                },
372            ],
373        };
374        let mut buf = BytesMut::new();
375        p.encode(&mut buf).unwrap();
376        let mut b = buf.freeze();
377        let d = ClientboundLoginSuccess::decode(&mut b).unwrap();
378        assert_eq!(d.uuid, p.uuid);
379        assert_eq!(d.properties.len(), 2);
380        assert_eq!(d.properties[0].name, "textures");
381        assert_eq!(d.properties[1].signature, None);
382    }
383
384    #[test]
385    fn encryption_request_roundtrip() {
386        let p = ClientboundEncryptionRequest {
387            server_id: String::new(),
388            public_key: vec![0xAB, 0xCD, 0xEF],
389            verify_token: vec![1, 2, 3, 4],
390            should_authenticate: true,
391        };
392        let mut buf = BytesMut::new();
393        p.encode(&mut buf).unwrap();
394        let mut b = buf.freeze();
395        assert_eq!(ClientboundEncryptionRequest::decode(&mut b).unwrap(), p);
396    }
397
398    #[test]
399    fn encryption_response_roundtrip() {
400        let p = ServerboundEncryptionResponse {
401            shared_secret: vec![0xFF; 16],
402            verify_token: vec![0x00; 4],
403        };
404        let mut buf = BytesMut::new();
405        p.encode(&mut buf).unwrap();
406        let mut b = buf.freeze();
407        assert_eq!(ServerboundEncryptionResponse::decode(&mut b).unwrap(), p);
408    }
409
410    #[test]
411    fn set_compression_roundtrip() {
412        let p = ClientboundSetCompression {
413            threshold: VarInt(512),
414        };
415        let mut buf = BytesMut::new();
416        p.encode(&mut buf).unwrap();
417        let mut b = buf.freeze();
418        assert_eq!(ClientboundSetCompression::decode(&mut b).unwrap(), p);
419    }
420}