use bytes::{Buf, BufMut, Bytes};
use uuid::Uuid;
use crate::types::{self, GameProfile, ProfileProperty, ProtocolError};
use crate::varint;
use super::Packet;
#[derive(Debug, Clone)]
pub struct LoginStartPacket {
pub username: String,
pub uuid: Uuid,
}
impl Packet for LoginStartPacket {
const PACKET_ID: i32 = 0x00;
fn decode(buf: &mut impl Buf) -> Result<Self, ProtocolError> {
let username = types::read_string_max(buf, 16)?;
let uuid = types::read_uuid(buf)?;
Ok(Self { username, uuid })
}
fn encode(&self, buf: &mut impl BufMut) {
types::write_string(buf, &self.username);
types::write_uuid(buf, self.uuid);
}
}
#[derive(Debug, Clone)]
pub struct EncryptionRequestPacket {
pub server_id: String,
pub public_key: Vec<u8>,
pub verify_token: Vec<u8>,
pub should_authenticate: bool,
}
impl Packet for EncryptionRequestPacket {
const PACKET_ID: i32 = 0x01;
#[allow(clippy::cast_sign_loss)]
fn decode(buf: &mut impl Buf) -> Result<Self, ProtocolError> {
let server_id = types::read_string_max(buf, 20)?;
let pk_len = varint::read_var_int(buf)? as usize;
if buf.remaining() < pk_len {
return Err(ProtocolError::UnexpectedEof);
}
let public_key = buf.copy_to_bytes(pk_len).to_vec();
let vt_len = varint::read_var_int(buf)? as usize;
if buf.remaining() < vt_len {
return Err(ProtocolError::UnexpectedEof);
}
let verify_token = buf.copy_to_bytes(vt_len).to_vec();
let should_authenticate = if buf.has_remaining() {
buf.get_u8() != 0
} else {
true
};
Ok(Self {
server_id,
public_key,
verify_token,
should_authenticate,
})
}
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
fn encode(&self, buf: &mut impl BufMut) {
types::write_string(buf, &self.server_id);
varint::write_var_int(buf, self.public_key.len() as i32);
buf.put_slice(&self.public_key);
varint::write_var_int(buf, self.verify_token.len() as i32);
buf.put_slice(&self.verify_token);
buf.put_u8(u8::from(self.should_authenticate));
}
}
#[derive(Debug, Clone)]
pub struct EncryptionResponsePacket {
pub shared_secret: Vec<u8>,
pub verify_token: Vec<u8>,
}
impl Packet for EncryptionResponsePacket {
const PACKET_ID: i32 = 0x01;
#[allow(clippy::cast_sign_loss)]
fn decode(buf: &mut impl Buf) -> Result<Self, ProtocolError> {
let ss_len = varint::read_var_int(buf)? as usize;
if buf.remaining() < ss_len {
return Err(ProtocolError::UnexpectedEof);
}
let shared_secret = buf.copy_to_bytes(ss_len).to_vec();
let vt_len = varint::read_var_int(buf)? as usize;
if buf.remaining() < vt_len {
return Err(ProtocolError::UnexpectedEof);
}
let verify_token = buf.copy_to_bytes(vt_len).to_vec();
Ok(Self {
shared_secret,
verify_token,
})
}
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
fn encode(&self, buf: &mut impl BufMut) {
varint::write_var_int(buf, self.shared_secret.len() as i32);
buf.put_slice(&self.shared_secret);
varint::write_var_int(buf, self.verify_token.len() as i32);
buf.put_slice(&self.verify_token);
}
}
#[derive(Debug, Clone)]
pub struct LoginSuccessPacket {
pub uuid: Uuid,
pub username: String,
pub properties: Vec<ProfileProperty>,
}
impl LoginSuccessPacket {
#[must_use]
pub fn from_profile(profile: &GameProfile) -> Self {
Self {
uuid: profile.id,
username: profile.name.clone(),
properties: profile.properties.clone(),
}
}
}
impl Packet for LoginSuccessPacket {
const PACKET_ID: i32 = 0x02;
fn decode(buf: &mut impl Buf) -> Result<Self, ProtocolError> {
let uuid = types::read_uuid(buf)?;
let username = types::read_string_max(buf, 16)?;
let properties = types::read_properties(buf)?;
Ok(Self {
uuid,
username,
properties,
})
}
fn encode(&self, buf: &mut impl BufMut) {
types::write_uuid(buf, self.uuid);
types::write_string(buf, &self.username);
types::write_properties(buf, &self.properties);
}
}
#[derive(Debug, Clone)]
pub struct SetCompressionPacket {
pub threshold: i32,
}
impl Packet for SetCompressionPacket {
const PACKET_ID: i32 = 0x03;
fn decode(buf: &mut impl Buf) -> Result<Self, ProtocolError> {
let threshold = varint::read_var_int(buf)?;
Ok(Self { threshold })
}
fn encode(&self, buf: &mut impl BufMut) {
varint::write_var_int(buf, self.threshold);
}
}
#[derive(Debug, Clone)]
pub struct LoginPluginRequestPacket {
pub message_id: i32,
pub channel: String,
pub data: Bytes,
}
impl Packet for LoginPluginRequestPacket {
const PACKET_ID: i32 = 0x04;
fn decode(buf: &mut impl Buf) -> Result<Self, ProtocolError> {
let message_id = varint::read_var_int(buf)?;
let channel = types::read_string(buf)?;
let data = buf.copy_to_bytes(buf.remaining());
Ok(Self {
message_id,
channel,
data,
})
}
fn encode(&self, buf: &mut impl BufMut) {
varint::write_var_int(buf, self.message_id);
types::write_string(buf, &self.channel);
buf.put_slice(&self.data);
}
}
#[derive(Debug, Clone)]
pub struct LoginPluginResponsePacket {
pub message_id: i32,
pub successful: bool,
pub data: Bytes,
}
impl Packet for LoginPluginResponsePacket {
const PACKET_ID: i32 = 0x02;
fn decode(buf: &mut impl Buf) -> Result<Self, ProtocolError> {
let message_id = varint::read_var_int(buf)?;
if !buf.has_remaining() {
return Err(ProtocolError::UnexpectedEof);
}
let successful = buf.get_u8() != 0;
let data = if successful {
buf.copy_to_bytes(buf.remaining())
} else {
Bytes::new()
};
Ok(Self {
message_id,
successful,
data,
})
}
fn encode(&self, buf: &mut impl BufMut) {
varint::write_var_int(buf, self.message_id);
buf.put_u8(u8::from(self.successful));
if self.successful {
buf.put_slice(&self.data);
}
}
}
#[derive(Debug, Clone)]
pub struct LoginAcknowledgedPacket;
impl Packet for LoginAcknowledgedPacket {
const PACKET_ID: i32 = 0x03;
fn decode(_buf: &mut impl Buf) -> Result<Self, ProtocolError> {
Ok(Self)
}
fn encode(&self, _buf: &mut impl BufMut) {}
}
#[derive(Debug, Clone)]
pub struct LoginDisconnectPacket {
pub reason: String,
}
impl Packet for LoginDisconnectPacket {
const PACKET_ID: i32 = 0x00;
fn decode(buf: &mut impl Buf) -> Result<Self, ProtocolError> {
let reason = types::read_string(buf)?;
Ok(Self { reason })
}
fn encode(&self, buf: &mut impl BufMut) {
types::write_string(buf, &self.reason);
}
}