use crate::error::Result;
use crate::packets::configuration::{
ClientboundConfigurationPacket, ServerboundConfigurationPacket,
};
use crate::packets::handshake::ServerboundHandshakePacket;
use crate::packets::login::{ClientboundLoginPacket, ServerboundLoginPacket};
use crate::packets::play::{ClientboundPlayPacket, ServerboundPlayPacket};
use crate::packets::status::{ClientboundStatusPacket, ServerboundStatusPacket};
use crate::version::ProtocolVersion;
#[derive(Debug)]
pub struct PacketRegistry {
version: ProtocolVersion,
}
impl PacketRegistry {
pub fn for_version(version: ProtocolVersion) -> Self {
Self { version }
}
pub fn version(&self) -> ProtocolVersion {
self.version
}
pub fn decode_serverbound_handshake(
&self,
id: i32,
buf: &mut &[u8],
) -> Result<ServerboundHandshakePacket> {
ServerboundHandshakePacket::decode_by_id(id, buf)
}
pub fn decode_serverbound_status(
&self,
id: i32,
buf: &mut &[u8],
) -> Result<ServerboundStatusPacket> {
ServerboundStatusPacket::decode_by_id(id, buf)
}
pub fn decode_clientbound_status(
&self,
id: i32,
buf: &mut &[u8],
) -> Result<ClientboundStatusPacket> {
ClientboundStatusPacket::decode_by_id(id, buf)
}
pub fn decode_serverbound_login(
&self,
id: i32,
buf: &mut &[u8],
) -> Result<ServerboundLoginPacket> {
ServerboundLoginPacket::decode_by_id(id, buf)
}
pub fn decode_clientbound_login(
&self,
id: i32,
buf: &mut &[u8],
) -> Result<ClientboundLoginPacket> {
ClientboundLoginPacket::decode_by_id(id, buf)
}
pub fn decode_serverbound_configuration(
&self,
id: i32,
buf: &mut &[u8],
) -> Result<ServerboundConfigurationPacket> {
ServerboundConfigurationPacket::decode_by_id(id, buf)
}
pub fn decode_clientbound_configuration(
&self,
id: i32,
buf: &mut &[u8],
) -> Result<ClientboundConfigurationPacket> {
ClientboundConfigurationPacket::decode_by_id(id, buf)
}
pub fn decode_serverbound_play(
&self,
id: i32,
buf: &mut &[u8],
) -> Result<ServerboundPlayPacket> {
ServerboundPlayPacket::decode_by_id(id, buf)
}
pub fn decode_clientbound_play(
&self,
id: i32,
buf: &mut &[u8],
) -> Result<ClientboundPlayPacket> {
ClientboundPlayPacket::decode_by_id(id, buf)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::packets::handshake::ServerboundHandshakeSetProtocol;
use crate::packets::status::{
ClientboundStatusPing, ClientboundStatusServerInfo, ServerboundStatusPing,
ServerboundStatusPingStart,
};
use basalt_types::{Encode, EncodedSize};
fn registry() -> PacketRegistry {
PacketRegistry::for_version(ProtocolVersion::V1_21)
}
#[test]
fn version() {
assert_eq!(registry().version(), ProtocolVersion::V1_21);
}
#[test]
fn decode_handshake() {
let packet = ServerboundHandshakeSetProtocol {
protocol_version: 767,
server_host: "localhost".into(),
server_port: 25565,
next_state: 1,
};
let mut buf = Vec::with_capacity(packet.encoded_size());
packet.encode(&mut buf).unwrap();
let mut cursor = buf.as_slice();
let result = registry()
.decode_serverbound_handshake(ServerboundHandshakeSetProtocol::PACKET_ID, &mut cursor)
.unwrap();
assert!(cursor.is_empty());
assert_eq!(result, ServerboundHandshakePacket::SetProtocol(packet));
}
#[test]
fn decode_status_request() {
let mut buf = Vec::new();
ServerboundStatusPingStart.encode(&mut buf).unwrap();
let mut cursor = buf.as_slice();
let result = registry()
.decode_serverbound_status(ServerboundStatusPingStart::PACKET_ID, &mut cursor)
.unwrap();
assert!(matches!(result, ServerboundStatusPacket::PingStart(_)));
}
#[test]
fn decode_ping_request() {
let packet = ServerboundStatusPing { time: 12345 };
let mut buf = Vec::new();
packet.encode(&mut buf).unwrap();
let mut cursor = buf.as_slice();
let result = registry()
.decode_serverbound_status(ServerboundStatusPing::PACKET_ID, &mut cursor)
.unwrap();
assert_eq!(
result,
ServerboundStatusPacket::Ping(ServerboundStatusPing { time: 12345 })
);
}
#[test]
fn decode_status_response() {
let packet = ClientboundStatusServerInfo {
response: "{}".into(),
};
let mut buf = Vec::new();
packet.encode(&mut buf).unwrap();
let mut cursor = buf.as_slice();
let result = registry()
.decode_clientbound_status(ClientboundStatusServerInfo::PACKET_ID, &mut cursor)
.unwrap();
assert_eq!(
result,
ClientboundStatusPacket::ServerInfo(ClientboundStatusServerInfo {
response: "{}".into()
})
);
}
#[test]
fn decode_ping_response() {
let packet = ClientboundStatusPing { time: 67890 };
let mut buf = Vec::new();
packet.encode(&mut buf).unwrap();
let mut cursor = buf.as_slice();
let result = registry()
.decode_clientbound_status(ClientboundStatusPing::PACKET_ID, &mut cursor)
.unwrap();
assert_eq!(
result,
ClientboundStatusPacket::Ping(ClientboundStatusPing { time: 67890 })
);
}
#[test]
fn unknown_handshake_packet() {
let mut cursor: &[u8] = &[];
assert!(
registry()
.decode_serverbound_handshake(0xFF, &mut cursor)
.is_err()
);
}
#[test]
fn unknown_status_serverbound() {
let mut cursor: &[u8] = &[];
assert!(
registry()
.decode_serverbound_status(0xFF, &mut cursor)
.is_err()
);
}
#[test]
fn unknown_status_clientbound() {
let mut cursor: &[u8] = &[];
assert!(
registry()
.decode_clientbound_status(0xFF, &mut cursor)
.is_err()
);
}
}