Skip to main content

kojacoord_protocol/versions/v1_6_4/login/
mod.rs

1use crate::codec::{Decode, Encode, PacketId};
2use crate::error::ProtocolError;
3use bytes::{Bytes, BytesMut};
4
5fn decode_legacy_string(src: &mut Bytes) -> Result<String, ProtocolError> {
6    if src.len() < 2 {
7        return Err(ProtocolError::UnexpectedEof);
8    }
9    let len = u16::from_be_bytes([src[0], src[1]]) as usize;
10    src.advance(2);
11    let byte_len = len * 2;
12    if src.len() < byte_len {
13        return Err(ProtocolError::UnexpectedEof);
14    }
15    let raw = src.copy_to_bytes(byte_len);
16    let chars: Vec<u16> = raw
17        .chunks(2)
18        .map(|c| u16::from_be_bytes([c[0], c[1]]))
19        .collect();
20    String::from_utf16(&chars).map_err(|_| ProtocolError::UnexpectedEof)
21}
22
23fn encode_legacy_string(s: &str, dst: &mut BytesMut) {
24    let utf16: Vec<u16> = s.encode_utf16().collect();
25    dst.extend_from_slice(&(utf16.len() as u16).to_be_bytes());
26    for ch in &utf16 {
27        dst.extend_from_slice(&ch.to_be_bytes());
28    }
29}
30
31use bytes::Buf;
32
33#[derive(Debug, Clone)]
34pub struct HandshakeC2S {
35    pub protocol_version: u8,
36    pub username: String,
37    pub host: String,
38    pub port: i32,
39}
40
41impl PacketId for HandshakeC2S {
42    fn packet_id(_ver: u32) -> u8 {
43        0x02
44    }
45}
46
47impl Encode for HandshakeC2S {
48    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
49        dst.extend_from_slice(&[self.protocol_version]);
50        encode_legacy_string(&self.username, dst);
51        encode_legacy_string(&self.host, dst);
52        dst.extend_from_slice(&self.port.to_be_bytes());
53        Ok(())
54    }
55}
56
57impl Decode for HandshakeC2S {
58    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
59        if src.is_empty() {
60            return Err(ProtocolError::UnexpectedEof);
61        }
62        let protocol_version = src.get_u8();
63        let username = decode_legacy_string(src)?;
64        let host = decode_legacy_string(src)?;
65        if src.remaining() < 4 {
66            return Err(ProtocolError::UnexpectedEof);
67        }
68        let port = src.get_i32();
69        Ok(Self {
70            protocol_version,
71            username,
72            host,
73            port,
74        })
75    }
76}
77
78#[derive(Debug, Clone)]
79pub struct EncryptionKeyRequestS2C {
80    pub server_id: String,
81    pub public_key: Vec<u8>,
82    pub verify_token: Vec<u8>,
83}
84
85impl PacketId for EncryptionKeyRequestS2C {
86    fn packet_id(_ver: u32) -> u8 {
87        0xFD
88    }
89}
90
91impl Encode for EncryptionKeyRequestS2C {
92    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
93        encode_legacy_string(&self.server_id, dst);
94        dst.extend_from_slice(&(self.public_key.len() as i16).to_be_bytes());
95        dst.extend_from_slice(&self.public_key);
96        dst.extend_from_slice(&(self.verify_token.len() as i16).to_be_bytes());
97        dst.extend_from_slice(&self.verify_token);
98        Ok(())
99    }
100}
101
102impl Decode for EncryptionKeyRequestS2C {
103    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
104        let server_id = decode_legacy_string(src)?;
105        if src.remaining() < 2 {
106            return Err(ProtocolError::UnexpectedEof);
107        }
108        let key_len = i16::from_be_bytes([src[0], src[1]]) as usize;
109        src.advance(2);
110        if src.remaining() < key_len {
111            return Err(ProtocolError::UnexpectedEof);
112        }
113        let public_key = src.copy_to_bytes(key_len).to_vec();
114        if src.remaining() < 2 {
115            return Err(ProtocolError::UnexpectedEof);
116        }
117        let tok_len = i16::from_be_bytes([src[0], src[1]]) as usize;
118        src.advance(2);
119        if src.remaining() < tok_len {
120            return Err(ProtocolError::UnexpectedEof);
121        }
122        let verify_token = src.copy_to_bytes(tok_len).to_vec();
123        Ok(Self {
124            server_id,
125            public_key,
126            verify_token,
127        })
128    }
129}
130
131#[derive(Debug, Clone)]
132pub struct EncryptionKeyResponseC2S {
133    pub shared_secret: Vec<u8>,
134    pub verify_token: Vec<u8>,
135}
136
137impl PacketId for EncryptionKeyResponseC2S {
138    fn packet_id(_ver: u32) -> u8 {
139        0xFC
140    }
141}
142
143impl Encode for EncryptionKeyResponseC2S {
144    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
145        dst.extend_from_slice(&(self.shared_secret.len() as i16).to_be_bytes());
146        dst.extend_from_slice(&self.shared_secret);
147        dst.extend_from_slice(&(self.verify_token.len() as i16).to_be_bytes());
148        dst.extend_from_slice(&self.verify_token);
149        Ok(())
150    }
151}
152
153impl Decode for EncryptionKeyResponseC2S {
154    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
155        if src.remaining() < 2 {
156            return Err(ProtocolError::UnexpectedEof);
157        }
158        let ss_len = i16::from_be_bytes([src[0], src[1]]) as usize;
159        src.advance(2);
160        if src.remaining() < ss_len {
161            return Err(ProtocolError::UnexpectedEof);
162        }
163        let shared_secret = src.copy_to_bytes(ss_len).to_vec();
164        if src.remaining() < 2 {
165            return Err(ProtocolError::UnexpectedEof);
166        }
167        let vt_len = i16::from_be_bytes([src[0], src[1]]) as usize;
168        src.advance(2);
169        if src.remaining() < vt_len {
170            return Err(ProtocolError::UnexpectedEof);
171        }
172        let verify_token = src.copy_to_bytes(vt_len).to_vec();
173        Ok(Self {
174            shared_secret,
175            verify_token,
176        })
177    }
178}
179
180#[derive(Debug, Clone)]
181pub struct LoginRequestS2C {
182    pub entity_id: i32,
183    pub level_type: String,
184    pub game_mode: u8,
185    pub dimension: i8,
186    pub difficulty: u8,
187    pub world_height: u8,
188    pub max_players: u8,
189}
190
191impl PacketId for LoginRequestS2C {
192    fn packet_id(_ver: u32) -> u8 {
193        0x01
194    }
195}
196
197impl Encode for LoginRequestS2C {
198    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
199        dst.extend_from_slice(&self.entity_id.to_be_bytes());
200        encode_legacy_string(&self.level_type, dst);
201        dst.extend_from_slice(&[
202            self.game_mode,
203            self.dimension as u8,
204            self.difficulty,
205            self.world_height,
206            self.max_players,
207        ]);
208        Ok(())
209    }
210}
211
212impl Decode for LoginRequestS2C {
213    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
214        if src.remaining() < 4 {
215            return Err(ProtocolError::UnexpectedEof);
216        }
217        let entity_id = src.get_i32();
218        let level_type = decode_legacy_string(src)?;
219        if src.remaining() < 5 {
220            return Err(ProtocolError::UnexpectedEof);
221        }
222        let game_mode = src.get_u8();
223        let dimension = src.get_i8();
224        let difficulty = src.get_u8();
225        let world_height = src.get_u8();
226        let max_players = src.get_u8();
227        Ok(Self {
228            entity_id,
229            level_type,
230            game_mode,
231            dimension,
232            difficulty,
233            world_height,
234            max_players,
235        })
236    }
237}
238
239#[derive(Debug, Clone)]
240pub struct ClientboundLoginDisconnect {
241    pub reason: String,
242}
243
244impl PacketId for ClientboundLoginDisconnect {
245    fn packet_id(_ver: u32) -> u8 {
246        0x00
247    }
248}
249
250impl Encode for ClientboundLoginDisconnect {
251    fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
252        encode_legacy_string(&self.reason, dst);
253        Ok(())
254    }
255}
256
257impl Decode for ClientboundLoginDisconnect {
258    fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
259        Ok(Self {
260            reason: decode_legacy_string(src)?,
261        })
262    }
263}