diff --git a/Cargo.toml b/Cargo.toml index 85ccf83..761ea9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,4 @@ readme = "README.md" name = "mcpl" [dependencies] +byteorder = "1" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..6753a1c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,27 @@ +use std::io; +use std::io::{Read, Write}; + +pub mod status; + +/// Current supported protocol version. +pub const PROTOCOL_VERSION: usize = 498; + +/// Possible errors while decoding packet. +pub enum DecodePacketError { + UnknownPacketType { type_id: u8 }, + IOError { io_error: io::Error }, +} + +impl From for DecodePacketError { + fn from(io_error: io::Error) -> Self { + DecodePacketError::IOError { io_error } + } +} + +trait Packet { + type Output; + + fn encode(&self, writer: &mut W) -> Result<(), io::Error>; + + fn decode(reader: &mut R) -> Result; +} diff --git a/src/status.rs b/src/status.rs new file mode 100644 index 0000000..2083f71 --- /dev/null +++ b/src/status.rs @@ -0,0 +1,100 @@ +use crate::{DecodePacketError, Packet}; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use std::io; +use std::io::{Read, Write}; + +pub enum StatusServerBoundPacket { + StatusRequest, + PingRequest(PingRequest), +} + +pub enum StatusClientBoundPacket { + StatusResponse, + PingResponse(PingResponse), +} + +impl StatusServerBoundPacket { + pub fn get_type_id(&self) -> u8 { + match self { + StatusServerBoundPacket::StatusRequest => 0x0, + StatusServerBoundPacket::PingRequest(_) => 0x1, + } + } + + pub fn decode(&self, type_id: u8, reader: &mut R) -> Result { + match type_id { + 0x0 => Ok(StatusServerBoundPacket::StatusRequest), + 0x1 => { + let ping_request = PingRequest::decode(reader)?; + + Ok(StatusServerBoundPacket::PingRequest(ping_request)) + } + _ => Err(DecodePacketError::UnknownPacketType { type_id }), + } + } +} + +impl StatusClientBoundPacket { + pub fn get_type_id(&self) -> u8 { + match self { + StatusClientBoundPacket::StatusResponse => 0x0, + StatusClientBoundPacket::PingResponse(_) => 0x1, + } + } +} + +pub struct PingRequest { + time: u64, +} + +impl PingRequest { + pub fn new(time: u64) -> StatusServerBoundPacket { + let ping_request = PingRequest { time }; + + StatusServerBoundPacket::PingRequest(ping_request) + } +} + +impl Packet for PingRequest { + type Output = Self; + + fn encode(&self, writer: &mut W) -> Result<(), io::Error> { + writer.write_u64::(self.time)?; + + Ok(()) + } + + fn decode(reader: &mut R) -> Result { + let time = reader.read_u64::()?; + + Ok(PingRequest { time }) + } +} + +pub struct PingResponse { + time: u64, +} + +impl PingResponse { + pub fn new(time: u64) -> StatusClientBoundPacket { + let ping_response = PingResponse { time }; + + StatusClientBoundPacket::PingResponse(ping_response) + } +} + +impl Packet for PingResponse { + type Output = Self; + + fn encode(&self, writer: &mut W) -> Result<(), io::Error> { + writer.write_u64::(self.time)?; + + Ok(()) + } + + fn decode(reader: &mut R) -> Result { + let time = reader.read_u64::()?; + + Ok(PingResponse { time }) + } +}