use std::io::{self, Read, Write};
use crate::network::packet::{Packet, PacketCodec};
use crate::protocol::types::{Boolean, ProtocolRead, ProtocolString, ProtocolWrite, VarInt};
use serde::Deserialize;
use tracing::debug;
use uuid::Uuid;
#[derive(Debug, Deserialize, Clone)]
pub struct Property {
pub name: ProtocolString,
pub value: ProtocolString,
pub signature: Option<ProtocolString>,
}
impl ProtocolWrite for Property {
fn write_to<W: Write>(&self, writer: &mut W) -> io::Result<usize> {
let mut written = 0;
written += self.name.write_to(writer)?;
written += self.value.write_to(writer)?;
written += Boolean(self.signature.is_some()).write_to(writer)?;
if let Some(ref sig) = self.signature {
written += sig.write_to(writer)?;
}
Ok(written)
}
}
#[derive(Debug, Clone)]
pub struct ClientBoundLoginSuccess {
pub uuid: Uuid,
pub username: ProtocolString,
pub properties: Vec<Property>,
}
impl From<&ClientBoundLoginSuccess> for Packet {
fn from(login: &ClientBoundLoginSuccess) -> Self {
let mut packet = Packet::new(0x02);
packet.data.extend_from_slice(login.uuid.as_bytes());
packet.encode(&login.username).unwrap();
packet
.encode(&VarInt(login.properties.len() as i32))
.unwrap();
packet
}
}
impl TryFrom<&Packet> for ClientBoundLoginSuccess {
type Error = io::Error;
fn try_from(packet: &Packet) -> Result<Self, Self::Error> {
let mut cursor = io::Cursor::new(&packet.data);
debug!(
"Parsing login success packet of length {}",
packet.data.len()
);
let mut uuid_bytes = [0u8; 16];
cursor.read_exact(&mut uuid_bytes)?;
let uuid = Uuid::from_bytes(uuid_bytes);
debug!("Read UUID: {:?}", uuid);
let (username, _) = ProtocolString::read_from(&mut cursor)?;
debug!("Read username: {}", username.0);
let (VarInt(count), _) = VarInt::read_from(&mut cursor)?;
debug!("Reading {} properties", count);
let mut properties = Vec::with_capacity(count as usize);
for i in 0..count {
let (name, _) = ProtocolString::read_from(&mut cursor)?;
let (value, _) = ProtocolString::read_from(&mut cursor)?;
let (Boolean(has_sig), _) = Boolean::read_from(&mut cursor)?;
let signature = if has_sig {
let (sig, _) = ProtocolString::read_from(&mut cursor)?;
Some(sig)
} else {
None
};
debug!(
"Read property {}: name={}, value={}, has_sig={}",
i, name.0, value.0, has_sig
);
properties.push(Property {
name,
value,
signature,
});
}
Ok(Self {
uuid,
username,
properties,
})
}
}