use crate::{Deserialize, DeserializeErr, Serialize, Serializer, SerializeResult}; use alloc::{string::String, fmt, vec::Vec, borrow::ToOwned}; #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum PacketDirection { ClientBound, ServerBound, } impl PacketDirection { pub fn opposite(&self) -> Self { use PacketDirection::*; match self { ClientBound => ServerBound, ServerBound => ClientBound, } } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum State { Handshaking, Status, Login, Play, } impl State { pub fn name(&self) -> String { use State::*; match self { Handshaking => "Handshaking", Status => "Status", Login => "Login", Play => "Play", } .to_owned() } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct Id { pub id: i32, pub state: State, pub direction: PacketDirection, } impl Serialize for Id { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_other(&crate::types::VarInt(self.id)) } } impl From<(i32, State, PacketDirection)> for Id { fn from(other: (i32, State, PacketDirection)) -> Self { let (id, state, direction) = other; Self { id, state, direction } } } impl From for (i32, State, PacketDirection) { fn from(id: Id) -> Self { let Id { id, state, direction } = id; (id, state, direction) } } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] pub struct ProtocolSpec { pub name: String, pub packets: Vec, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] pub struct ProtocolPacketSpec { pub state: String, pub direction: String, pub id: i32, pub name: String, pub body_struct: String, pub fields: Vec, } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] pub struct ProtocolPacketField { pub name: String, pub kind: String, } pub trait HasPacketKind { type Kind: PacketKind; fn kind(&self) -> Self::Kind; } pub trait PacketKind: HasPacketId + Clone + Copy + PartialEq + Eq { #[cfg(feature = "gat")] type RawPacket<'a>: RawPacket<'a>; fn from_id(id: Id) -> Option; #[cfg(feature = "gat")] fn with_body_data<'a>(self, body: &'a [u8]) -> Self::RawPacket<'a>; } pub trait HasPacketId { fn id(&self) -> Id; fn version() -> crate::types::VarInt; } pub trait HasPacketBody { fn mc_serialize_body(&self, to: &mut S) -> SerializeResult where S: Serializer; } pub trait RawPacket<'a>: HasPacketId + Sized { type Packet: Packet; fn create(id: Id, data: &'a [u8]) -> Result; fn data(&self) -> &'a [u8]; fn deserialize(&self) -> Result; } pub trait Packet: HasPacketId + HasPacketBody + Sized {} #[derive(Clone)] pub enum PacketErr { UnknownId(Id), DeserializeFailed(DeserializeErr), ExtraData(Vec), } impl fmt::Display for PacketErr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use PacketErr::*; match self { UnknownId(id) => f.write_fmt(format_args!("unknown packet id {:?}", id)), DeserializeFailed(err) => { f.write_fmt(format_args!("failed to deserialize packet: {:?}", err)) } ExtraData(data) => f.write_fmt(format_args!( "extra data unparsed at end of packet: {:?}", data )), } } } impl fmt::Debug for PacketErr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ::fmt(self, f) } } #[cfg(feature = "std")] impl std::error::Error for PacketErr {} pub trait ProtocolType: Serialize + Deserialize {} impl ProtocolType for T {} #[cfg(all(test, feature = "std"))] pub trait TestRandom { fn test_gen_random() -> Self; } #[macro_export] macro_rules! as_item { ($i:item) => { $i }; } #[macro_export] macro_rules! proto_struct { ($bodyt: ident { }) => { #[derive(Debug, Clone, PartialEq, Default)] pub struct $bodyt; impl Serialize for $bodyt { fn mc_serialize(&self, _: &mut S) -> SerializeResult { Ok(()) } } impl Deserialize for $bodyt { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Deserialized::ok(Self::default(), data) } } #[cfg(all(test, feature = "std"))] impl TestRandom for $bodyt { fn test_gen_random() -> Self { Self::default() } } }; ($bodyt: ident $(<$($g: ident),*>)? { $($fname: ident: $ftyp: ty ),+ }) => { $crate::as_item! { #[derive(Debug, Clone, PartialEq)] pub struct $bodyt$(<$($g),*> where $($g: alloc::fmt::Debug + Clone + PartialEq),*)? { $(pub $fname: $ftyp),+ } } impl$(<$($g),*>)? Serialize for $bodyt$(<$($g),*> where $($g: Serialize + alloc::fmt::Debug + Clone + PartialEq),*)? { fn mc_serialize(&self, to: &mut S) -> SerializeResult { $( to.serialize_other(&self.$fname)?; )+ Ok(()) } } impl$(<$($g),*>)? Deserialize for $bodyt$(<$($g),*> where $($g: Deserialize + alloc::fmt::Debug + Clone + PartialEq),*)? { fn mc_deserialize(_rest: &[u8]) -> DeserializeResult<'_, Self> { $(let Deserialized{ value: $fname, data: _rest } = <$ftyp>::mc_deserialize(_rest)?;)+ Deserialized::ok(Self{ $($fname),+ }, _rest) } } #[allow(unused_parens)] impl$(<$($g),*>)? From<($($ftyp),+)> for $bodyt$(<$($g),*>)? $(where $($g: alloc::fmt::Debug + Clone + PartialEq),*)? { fn from(other: ($($ftyp),+)) -> Self { let ($($fname),+) = other; Self { $($fname),+ } } } #[allow(unused_parens)] impl$(<$($g),*>)? From<$bodyt$(<$($g),*>)?> for ($($ftyp),+) $(where $($g: alloc::fmt::Debug + Clone + PartialEq),*)? { fn from(other: $bodyt$(<$($g),*>)?) -> Self { ($(other.$fname),+) } } #[cfg(all(test, feature = "std"))] impl$(<$($g),*>)? TestRandom for $bodyt$(<$($g),*> where $($g: TestRandom + alloc::fmt::Debug + Clone + PartialEq),*)? { fn test_gen_random() -> Self { Self{ $($fname: <$ftyp>::test_gen_random()),+ } } } } } #[macro_export] macro_rules! define_protocol { ($version: literal, $packett: ident, $rawpackett: ident, $rawdt: ident, $kindt: ident => { $($nam: ident, $id: literal, $state: ident, $direction: ident => $body: ident { $($fnam: ident: $ftyp: ty),* }),* } ) => { $crate::as_item! { #[derive(Debug, PartialEq, Clone)] pub enum $packett { $($nam($body)),*, } } $crate::as_item! { #[derive(Debug, PartialEq)] pub enum $rawpackett<'a> { $($nam($rawdt<'a, $body>)),*, } } $crate::as_item! { #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub enum $kindt { $($nam),*, } } impl crate::protocol::HasPacketKind for $packett { type Kind = $kindt; fn kind(&self) -> Self::Kind { match self { $($packett::$nam(_) => $kindt::$nam),*, } } } impl crate::protocol::HasPacketId for $packett { fn version() -> crate::types::VarInt { crate::types::VarInt($version) } fn id(&self) -> crate::protocol::Id { crate::protocol::HasPacketKind::kind(self).id() } } impl crate::protocol::HasPacketBody for $packett { fn mc_serialize_body(&self, to: &mut S) -> crate::SerializeResult where S: crate::Serializer { use self::$packett::*; match self { $($nam(body) => to.serialize_other(body)),+ } } } impl crate::protocol::Packet for $packett {} impl $packett { pub fn describe() -> crate::protocol::ProtocolSpec { crate::protocol::ProtocolSpec { name: stringify!($packett).to_owned(), packets: alloc::vec!( $(crate::protocol::ProtocolPacketSpec{ state: stringify!($state).to_owned(), direction: stringify!($direction).to_owned(), id: $id, name: stringify!($nam).to_owned(), body_struct: stringify!($body).to_owned(), fields: alloc::vec!( $(crate::protocol::ProtocolPacketField{ name: stringify!($fnam).to_owned(), kind: stringify!($ftyp).to_owned(), }),* ) }),*, ) } } } impl<'a> crate::protocol::HasPacketKind for $rawpackett<'a> { type Kind = $kindt; fn kind(&self) -> Self::Kind { match self { $($rawpackett::$nam(_) => $kindt::$nam),*, } } } impl<'a> crate::protocol::HasPacketId for $rawpackett<'a> { fn id(&self) -> crate::protocol::Id { crate::protocol::HasPacketKind::kind(self).id() } fn version() -> crate::types::VarInt { crate::types::VarInt($version) } } impl<'a> crate::protocol::RawPacket<'a> for $rawpackett<'a> { type Packet = $packett; fn create(id: crate::protocol::Id, data: &'a[u8]) -> Result { use crate::protocol::PacketKind; if let Some(kind) = $kindt::from_id(id) { Ok(kind.with_body_data(data)) } else { Err(crate::protocol::PacketErr::UnknownId(id)) } } fn data(&self) -> &'a [u8] { use self::$rawpackett::*; match self { $($nam(bod) => bod.data),* } } fn deserialize(&self) -> Result { use crate::protocol::PacketErr::{ExtraData, DeserializeFailed}; match self { $($rawpackett::$nam(bod) => { let Deserialized { value: body, data: rest } = $body::mc_deserialize(bod.data) .map_err(move |err| DeserializeFailed(err))?; if !rest.is_empty() { Err(ExtraData(rest.to_vec())) } else { Ok($packett::$nam(body)) } }),*, } } } #[derive(PartialEq, Debug)] pub struct $rawdt<'a, T> { pub data: &'a [u8], _typ: core::marker::PhantomData } impl<'a, T> $rawdt<'a, T> where T: crate::Deserialize { pub fn deserialize(&self) -> Result { use crate::protocol::PacketErr::*; let Deserialized { value: body, data: rest } = T::mc_deserialize(self.data).map_err(DeserializeFailed)?; if !rest.is_empty() { Err(ExtraData(rest.to_vec())) } else { Ok(body) } } } impl crate::protocol::HasPacketId for $kindt { fn id(&self) -> crate::protocol::Id { use self::$kindt::*; use crate::protocol::State::*; use crate::protocol::PacketDirection::*; match self { $($nam => ($id, $state, $direction)),* }.into() } fn version() -> crate::types::VarInt { crate::types::VarInt($version) } } impl crate::protocol::PacketKind for $kindt { #[cfg(feature = "gat")] type RawPacket<'a> = $rawpackett<'a>; fn from_id(id: crate::protocol::Id) -> Option { match (id.id, id.state, id.direction) { $(($id, crate::protocol::State::$state, crate::protocol::PacketDirection::$direction) => Some($kindt::$nam)),*, _ => None } } #[cfg(feature = "gat")] fn with_body_data<'a>(self, data: &'a [u8]) -> Self::RawPacket<'a> { self.with_body_data_inner(data) } } #[cfg(not(feature = "gat"))] impl $kindt { pub fn with_body_data<'a>(self, data: &'a [u8]) -> $rawpackett<'a> { self.with_body_data_inner(data) } } impl $kindt { fn with_body_data_inner<'a>(self, data: &'a [u8]) -> $rawpackett<'a> { match self { $($kindt::$nam => $rawpackett::$nam($rawdt{ data, _typ: core::marker::PhantomData, })),*, } } } $($crate::proto_struct!($body { $($fnam: $ftyp),* });)* }; } #[macro_export] macro_rules! strip_plus { (+ $($rest: tt)*) => { $($rest)* } } #[macro_export] macro_rules! proto_enum_deserialize_variant { ($data: ident, $ty: ident :: $nam: ident ($bod: ty)) => { Ok(<$bod>::mc_deserialize($data)?.map(move |body| $ty::$nam(body))) }; ($data: ident, $ty: ident :: $nam: ident) => { Deserialized::ok($ty::$nam, $data) }; } #[macro_export] macro_rules! instead_of_ident { ($ident: tt, $replacement: tt) => { $replacement } } #[macro_export] macro_rules! proto_enum_with_type { ($typ: ty, $typname: ident, $(($bval: literal, $nam: ident $(($bod: ty))?)),*) => { $crate::as_item! { #[derive(PartialEq, Clone, Debug)] pub enum $typname { $($nam $(($bod))?),* } } impl Serialize for $typname { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let id_to_serialize: $typ = match self { $($typname::$nam$((instead_of_ident!($bod, _)))? => $bval),* }.into(); to.serialize_other(&id_to_serialize)?; self.serialize_body(to) } } impl Deserialize for $typname { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { <$typ>::mc_deserialize(data)?.and_then(move |id, rest| { Self::deserialize_with_id(id, rest) }) } } impl $typname { pub const fn variant_count() -> usize { crate::strip_plus!($(+ crate::instead_of_ident!($bval, 1))+) } pub fn deserialize_with_id<'a>(id: $typ, data: &'a[u8]) -> DeserializeResult<'a, Self> { match id.into() { $($bval => proto_enum_deserialize_variant!(data, $typname::$nam $(($bod))?)),*, other => { return Err(DeserializeErr::CannotUnderstandValue(alloc::format!("invalid {} {:?}", stringify!($typname), other))) } } } pub fn name(&self) -> &str { match self { $($typname::$nam$((instead_of_ident!($bod, _)))? => stringify!($nam)),* } } pub fn id(&self) -> $typ { match self { $($typname::$nam$((instead_of_ident!($bod, _)))? => $bval.into()),* } } #[allow(unused_variables)] pub fn serialize_body(&self, to: &mut S) -> SerializeResult { match &self { $($typname::$nam$((instead_of_ident!($bod, bod)))? => { $(to.serialize_other(instead_of_ident!($bod, bod))?;)? Ok(()) }),* } } } #[cfg(all(test, feature = "std"))] impl TestRandom for $typname { fn test_gen_random() -> Self { let mut rng = rand::thread_rng(); use rand::distributions::Distribution; let distr = rand::distributions::Uniform::new(1, Self::variant_count() + 1); let mut idx: usize = distr.sample(&mut rng); $( idx -= 1; if idx == 0 { return $typname::$nam$((<$bod>::test_gen_random()))?; } )+ panic!("cannot generate random {}", stringify!($typname)); } } } } #[macro_export] macro_rules! proto_byte_enum { ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => { proto_enum_with_type!(u8, $typname, $(($bval, $nam $(($bod))?)),*); } } #[macro_export] macro_rules! proto_varint_enum { ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => { proto_enum_with_type!(VarInt, $typname, $(($bval, $nam $(($bod))?)),*); } } #[macro_export] macro_rules! proto_int_enum { ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => { proto_enum_with_type!(i32, $typname, $(($bval, $nam $(($bod))?)),*); } } #[macro_export] macro_rules! proto_str_enum { ($typname: ident, $($sval: literal :: $nam: ident $(($bod: ident))?),*) => { crate::as_item! { #[derive(PartialEq, Clone, Debug)] pub enum $typname { $($nam $(($bod))?),* } } impl Serialize for $typname { fn mc_serialize(&self, to: &mut S) -> SerializeResult { let name = self.name().to_owned(); to.serialize_other(&name)?; self.serialize_body(to) } } impl Deserialize for $typname { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { String::mc_deserialize(data)?.and_then(move |name, rest| { Self::deserialize_with_id(name.as_str(), rest) }) } } impl $typname { pub const fn variant_count() -> usize { crate::strip_plus!($(+ crate::instead_of_ident!($sval, 1))+) } pub fn name(&self) -> &str { match self { $($typname::$nam$((instead_of_ident!($bod, _)))? => $sval),+, } } pub fn id(&self) -> String { self.name().to_owned() } pub fn deserialize_with_id<'a>(name: &str, data: &'a[u8]) -> DeserializeResult<'a, Self> { match name { $($sval => proto_enum_deserialize_variant!(data, $typname::$nam $(($bod))?)),*, other => Err(DeserializeErr::CannotUnderstandValue(alloc::format!("invalid {} ident '{}'", stringify!($typname), other))) } } #[allow(unused_variables)] pub fn serialize_body(&self, to: &mut S) -> SerializeResult { match &self { $($typname::$nam$((instead_of_ident!($bod, bod)))? => { $(to.serialize_other(instead_of_ident!($bod, bod))?;)? Ok(()) }),* } } } impl From<&$typname> for String { fn from(arg: &$typname) -> Self { arg.name().to_owned() } } impl From<$typname> for String { fn from(arg: $typname) -> Self { arg.name().to_owned() } } #[cfg(all(test, feature = "std"))] impl TestRandom for $typname { fn test_gen_random() -> Self { let mut rng = rand::thread_rng(); use rand::distributions::Distribution; let distr = rand::distributions::Uniform::new(1, Self::variant_count() + 1); let mut idx: usize = distr.sample(&mut rng); $( idx -= 1; if idx == 0 { return $typname::$nam$(($bod::test_gen_random()))?; } )+ panic!("cannot generate random {}", stringify!($typname)); } } } } #[macro_export] macro_rules! proto_byte_flag { ($typname: ident, $($bval: literal :: $isnam: ident $setnam: ident),*) => { #[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] pub struct $typname(pub u8); impl $typname { $(pub fn $isnam(&self) -> bool { self.0 & $bval != 0 } pub fn $setnam(&mut self, value: bool) { if value { self.0 |= $bval; } else { self.0 ^= $bval & self.0; } })+ } impl Serialize for $typname { fn mc_serialize(&self, to: &mut S) -> SerializeResult { to.serialize_byte(self.0) } } impl Deserialize for $typname { fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> { Ok(u8::mc_deserialize(data)?.map(move |b| $typname(b))) } } #[cfg(all(test, feature = "std"))] impl TestRandom for $typname { fn test_gen_random() -> Self { let mut out = <$typname>::default(); $( out.$setnam(rand::random::()); )+ out } } } }