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<S: Serializer>(&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<Id> 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<ProtocolPacketSpec>,
}
#[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<ProtocolPacketField>,
}
#[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<Self>;
#[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<S>(&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<Self, PacketErr>;
fn data(&self) -> &'a [u8];
fn deserialize(&self) -> Result<Self::Packet, PacketErr>;
}
pub trait Packet: HasPacketId + HasPacketBody + Sized {}
pub enum PacketErr {
UnknownId(Id),
DeserializeFailed(DeserializeErr),
ExtraData(Vec<u8>),
}
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 {
<dyn fmt::Display>::fmt(self, f)
}
}
#[cfg(feature = "std")]
impl std::error::Error for PacketErr {}
pub trait ProtocolType: Serialize + Deserialize {}
impl<T: Serialize + Deserialize> 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<S: Serializer>(&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<S: Serializer>(&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<S>(&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<Self, crate::protocol::PacketErr> {
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<Self::Packet, crate::protocol::PacketErr> {
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<T>
}
impl<'a, T> $rawdt<'a, T> where T: crate::Deserialize {
pub fn deserialize(&self) -> Result<T, crate::protocol::PacketErr> {
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<Self> {
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<S: Serializer>(&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<S: Serializer>(&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<S: Serializer>(&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<S: Serializer>(&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<S: Serializer>(&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::<bool>());
)+
out
}
}
}
}