Skip to main content

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