mcproto_rs/
protocol.rs

1use crate::{Deserialize, DeserializeErr, Serialize, Serializer, SerializeResult};
2use alloc::{string::String, fmt, vec::Vec, borrow::ToOwned};
3
4#[derive(Debug, PartialEq, Eq, Clone, Copy)]
5pub enum PacketDirection {
6    ClientBound,
7    ServerBound,
8}
9
10impl PacketDirection {
11    pub fn opposite(&self) -> Self {
12        use PacketDirection::*;
13        match self {
14            ClientBound => ServerBound,
15            ServerBound => ClientBound,
16        }
17    }
18}
19
20#[derive(Debug, PartialEq, Eq, Clone, Copy)]
21pub enum State {
22    Handshaking,
23    Status,
24    Login,
25    Play,
26}
27
28impl State {
29    pub fn name(&self) -> String {
30        use State::*;
31        match self {
32            Handshaking => "Handshaking",
33            Status => "Status",
34            Login => "Login",
35            Play => "Play",
36        }
37            .to_owned()
38    }
39}
40
41#[derive(Debug, PartialEq, Eq, Clone, Copy)]
42pub struct Id {
43    pub id: i32,
44    pub state: State,
45    pub direction: PacketDirection,
46}
47
48impl Serialize for Id {
49    fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
50        to.serialize_other(&crate::types::VarInt(self.id))
51    }
52}
53
54impl From<(i32, State, PacketDirection)> for Id {
55    fn from(other: (i32, State, PacketDirection)) -> Self {
56        let (id, state, direction) = other;
57        Self { id, state, direction }
58    }
59}
60
61impl From<Id> for (i32, State, PacketDirection) {
62    fn from(id: Id) -> Self {
63        let Id { id, state, direction } = id;
64        (id, state, direction)
65    }
66}
67
68#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
69pub struct ProtocolSpec {
70    pub name: String,
71    pub packets: Vec<ProtocolPacketSpec>,
72}
73
74#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
75pub struct ProtocolPacketSpec {
76    pub state: String,
77    pub direction: String,
78    pub id: i32,
79    pub name: String,
80    pub body_struct: String,
81    pub fields: Vec<ProtocolPacketField>,
82}
83
84#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)]
85pub struct ProtocolPacketField {
86    pub name: String,
87    pub kind: String,
88}
89
90pub trait HasPacketKind {
91    type Kind: PacketKind;
92
93    fn kind(&self) -> Self::Kind;
94}
95
96pub trait PacketKind: HasPacketId + Clone + Copy + PartialEq + Eq {
97
98    #[cfg(feature = "gat")]
99    type RawPacket<'a>: RawPacket<'a>;
100
101    fn from_id(id: Id) -> Option<Self>;
102
103    #[cfg(feature = "gat")]
104    fn with_body_data<'a>(self, body: &'a [u8]) -> Self::RawPacket<'a>;
105}
106
107pub trait HasPacketId {
108
109    fn id(&self) -> Id;
110
111    fn version() -> crate::types::VarInt;
112}
113
114pub trait HasPacketBody {
115
116    fn mc_serialize_body<S>(&self, to: &mut S) -> SerializeResult where S: Serializer;
117}
118
119pub trait RawPacket<'a>: HasPacketId + Sized {
120
121    type Packet: Packet;
122
123    fn create(id: Id, data: &'a [u8]) -> Result<Self, PacketErr>;
124
125    fn data(&self) -> &'a [u8];
126
127    fn deserialize(&self) -> Result<Self::Packet, PacketErr>;
128}
129
130pub trait Packet: HasPacketId + HasPacketBody + Sized {}
131
132pub enum PacketErr {
133    UnknownId(Id),
134    DeserializeFailed(DeserializeErr),
135    ExtraData(Vec<u8>),
136}
137
138impl fmt::Display for PacketErr {
139    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140        use PacketErr::*;
141        match self {
142            UnknownId(id) => f.write_fmt(format_args!("unknown packet id {:?}", id)),
143            DeserializeFailed(err) => {
144                f.write_fmt(format_args!("failed to deserialize packet: {:?}", err))
145            }
146            ExtraData(data) => f.write_fmt(format_args!(
147                "extra data unparsed at end of packet: {:?}",
148                data
149            )),
150        }
151    }
152}
153
154impl fmt::Debug for PacketErr {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        <dyn fmt::Display>::fmt(self, f)
157    }
158}
159
160#[cfg(feature = "std")]
161impl std::error::Error for PacketErr {}
162
163pub trait ProtocolType: Serialize + Deserialize {}
164
165impl<T: Serialize + Deserialize> ProtocolType for T {}
166
167#[cfg(all(test, feature = "std"))]
168pub trait TestRandom {
169    fn test_gen_random() -> Self;
170}
171
172#[macro_export]
173macro_rules! as_item {
174    ($i:item) => {
175        $i
176    };
177}
178
179#[macro_export]
180macro_rules! proto_struct {
181    ($bodyt: ident { }) => {
182        #[derive(Debug, Clone, PartialEq, Default)]
183        pub struct $bodyt;
184
185        impl Serialize for $bodyt {
186            fn mc_serialize<S: Serializer>(&self, _: &mut S) -> SerializeResult {
187                Ok(())
188            }
189        }
190
191        impl Deserialize for $bodyt {
192            fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
193                Deserialized::ok(Self::default(), data)
194            }
195        }
196
197        #[cfg(all(test, feature = "std"))]
198        impl TestRandom for $bodyt {
199            fn test_gen_random() -> Self {
200                Self::default()
201            }
202        }
203    };
204    ($bodyt: ident $(<$($g: ident),*>)? {
205        $($fname: ident: $ftyp: ty ),+
206    }) => {
207        $crate::as_item! {
208            #[derive(Debug, Clone, PartialEq)]
209            pub struct $bodyt$(<$($g),*> where $($g: alloc::fmt::Debug + Clone + PartialEq),*)? {
210               $(pub $fname: $ftyp),+
211            }
212        }
213
214        impl$(<$($g),*>)? Serialize for $bodyt$(<$($g),*> where $($g: Serialize + alloc::fmt::Debug + Clone + PartialEq),*)? {
215            fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
216                $(
217                    to.serialize_other(&self.$fname)?;
218                )+
219                Ok(())
220            }
221        }
222
223        impl$(<$($g),*>)? Deserialize for $bodyt$(<$($g),*> where $($g: Deserialize + alloc::fmt::Debug + Clone + PartialEq),*)? {
224            fn mc_deserialize(_rest: &[u8]) -> DeserializeResult<'_, Self> {
225                $(let Deserialized{ value: $fname, data: _rest } = <$ftyp>::mc_deserialize(_rest)?;)+
226
227                Deserialized::ok(Self{ $($fname),+ }, _rest)
228            }
229        }
230
231        #[allow(unused_parens)]
232        impl$(<$($g),*>)? From<($($ftyp),+)> for $bodyt$(<$($g),*>)? $(where $($g: alloc::fmt::Debug + Clone + PartialEq),*)? {
233            fn from(other: ($($ftyp),+)) -> Self {
234                let ($($fname),+) = other;
235                Self { $($fname),+ }
236            }
237        }
238
239        #[allow(unused_parens)]
240        impl$(<$($g),*>)? From<$bodyt$(<$($g),*>)?> for ($($ftyp),+) $(where $($g: alloc::fmt::Debug + Clone + PartialEq),*)? {
241            fn from(other: $bodyt$(<$($g),*>)?) -> Self {
242                ($(other.$fname),+)
243            }
244        }
245
246        #[cfg(all(test, feature = "std"))]
247        impl$(<$($g),*>)? TestRandom for $bodyt$(<$($g),*> where $($g: TestRandom + alloc::fmt::Debug + Clone + PartialEq),*)? {
248            fn test_gen_random() -> Self {
249                Self{ $($fname: <$ftyp>::test_gen_random()),+ }
250            }
251        }
252    }
253}
254
255#[macro_export]
256macro_rules! define_protocol {
257    ($version: literal, $packett: ident, $rawpackett: ident, $rawdt: ident, $kindt: ident => {
258        $($nam: ident, $id: literal, $state: ident, $direction: ident => $body: ident {
259            $($fnam: ident: $ftyp: ty),* }),*
260        }
261    ) => {
262        $crate::as_item! {
263            #[derive(Debug, PartialEq, Clone)]
264            pub enum $packett {
265                $($nam($body)),*,
266            }
267        }
268
269        $crate::as_item! {
270            #[derive(Debug, PartialEq)]
271            pub enum $rawpackett<'a> {
272                $($nam($rawdt<'a, $body>)),*,
273            }
274        }
275
276        $crate::as_item! {
277            #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
278            pub enum $kindt {
279                $($nam),*,
280            }
281        }
282
283        impl crate::protocol::HasPacketKind for $packett {
284            type Kind = $kindt;
285
286            fn kind(&self) -> Self::Kind {
287                match self {
288                    $($packett::$nam(_) => $kindt::$nam),*,
289                }
290            }
291        }
292
293        impl crate::protocol::HasPacketId for $packett {
294            fn version() -> crate::types::VarInt {
295                crate::types::VarInt($version)
296            }
297
298            fn id(&self) -> crate::protocol::Id {
299                crate::protocol::HasPacketKind::kind(self).id()
300            }
301        }
302
303        impl crate::protocol::HasPacketBody for $packett {
304            fn mc_serialize_body<S>(&self, to: &mut S) -> crate::SerializeResult where S: crate::Serializer {
305                use self::$packett::*;
306                match self {
307                    $($nam(body) => to.serialize_other(body)),+
308                }
309            }
310        }
311
312        impl crate::protocol::Packet for $packett {}
313
314        impl $packett {
315            pub fn describe() -> crate::protocol::ProtocolSpec {
316                crate::protocol::ProtocolSpec {
317                    name: stringify!($packett).to_owned(),
318                    packets: alloc::vec!(
319                        $(crate::protocol::ProtocolPacketSpec{
320                            state: stringify!($state).to_owned(),
321                            direction: stringify!($direction).to_owned(),
322                            id: $id,
323                            name: stringify!($nam).to_owned(),
324                            body_struct: stringify!($body).to_owned(),
325                            fields: alloc::vec!(
326                                $(crate::protocol::ProtocolPacketField{
327                                    name: stringify!($fnam).to_owned(),
328                                    kind: stringify!($ftyp).to_owned(),
329                                }),*
330                            )
331                        }),*,
332                    )
333                }
334            }
335        }
336
337        impl<'a> crate::protocol::HasPacketKind for $rawpackett<'a> {
338            type Kind = $kindt;
339
340            fn kind(&self) -> Self::Kind {
341                match self {
342                    $($rawpackett::$nam(_) => $kindt::$nam),*,
343                }
344            }
345        }
346
347        impl<'a> crate::protocol::HasPacketId for $rawpackett<'a> {
348            fn id(&self) -> crate::protocol::Id {
349                crate::protocol::HasPacketKind::kind(self).id()
350            }
351
352            fn version() -> crate::types::VarInt {
353                crate::types::VarInt($version)
354            }
355        }
356
357        impl<'a> crate::protocol::RawPacket<'a> for $rawpackett<'a> {
358
359            type Packet = $packett;
360
361            fn create(id: crate::protocol::Id, data: &'a[u8]) -> Result<Self, crate::protocol::PacketErr> {
362                use crate::protocol::PacketKind;
363                if let Some(kind) = $kindt::from_id(id) {
364                    Ok(kind.with_body_data(data))
365                } else {
366                    Err(crate::protocol::PacketErr::UnknownId(id))
367                }
368            }
369
370            fn data(&self) -> &'a [u8] {
371                use self::$rawpackett::*;
372
373                match self {
374                    $($nam(bod) => bod.data),*
375                }
376            }
377
378            fn deserialize(&self) -> Result<Self::Packet, crate::protocol::PacketErr> {
379                use crate::protocol::PacketErr::{ExtraData, DeserializeFailed};
380
381                match self {
382                    $($rawpackett::$nam(bod) => {
383                        let Deserialized { value: body, data: rest } =
384                            $body::mc_deserialize(bod.data)
385                                .map_err(move |err| DeserializeFailed(err))?;
386                        if !rest.is_empty() {
387                            Err(ExtraData(rest.to_vec()))
388                        } else {
389                            Ok($packett::$nam(body))
390                        }
391                    }),*,
392                }
393            }
394        }
395
396        #[derive(PartialEq, Debug)]
397        pub struct $rawdt<'a, T> {
398            pub data: &'a [u8],
399            _typ: core::marker::PhantomData<T>
400        }
401
402        impl<'a, T> $rawdt<'a, T> where T: crate::Deserialize {
403            pub fn deserialize(&self) -> Result<T, crate::protocol::PacketErr> {
404                use crate::protocol::PacketErr::*;
405
406                let Deserialized { value: body, data: rest } = T::mc_deserialize(self.data).map_err(DeserializeFailed)?;
407                if !rest.is_empty() {
408                    Err(ExtraData(rest.to_vec()))
409                } else {
410                    Ok(body)
411                }
412            }
413        }
414
415        impl crate::protocol::HasPacketId for $kindt {
416            fn id(&self) -> crate::protocol::Id {
417                use self::$kindt::*;
418                use crate::protocol::State::*;
419                use crate::protocol::PacketDirection::*;
420
421                match self {
422                    $($nam => ($id, $state, $direction)),*
423                }.into()
424            }
425
426            fn version() -> crate::types::VarInt {
427                crate::types::VarInt($version)
428            }
429        }
430
431        impl crate::protocol::PacketKind for $kindt {
432            #[cfg(feature = "gat")]
433            type RawPacket<'a> = $rawpackett<'a>;
434
435            fn from_id(id: crate::protocol::Id) -> Option<Self> {
436                match (id.id, id.state, id.direction) {
437                    $(($id, crate::protocol::State::$state, crate::protocol::PacketDirection::$direction) => Some($kindt::$nam)),*,
438                    _ => None
439                }
440            }
441
442            #[cfg(feature = "gat")]
443            fn with_body_data<'a>(self, data: &'a [u8]) -> Self::RawPacket<'a> {
444                self.with_body_data_inner(data)
445            }
446        }
447
448        #[cfg(not(feature = "gat"))]
449        impl $kindt {
450            pub fn with_body_data<'a>(self, data: &'a [u8]) -> $rawpackett<'a> {
451                self.with_body_data_inner(data)
452            }
453        }
454
455        impl $kindt {
456            fn with_body_data_inner<'a>(self, data: &'a [u8]) -> $rawpackett<'a> {
457                match self {
458                    $($kindt::$nam => $rawpackett::$nam($rawdt{
459                        data,
460                        _typ: core::marker::PhantomData,
461                    })),*,
462                }
463            }
464        }
465
466        $($crate::proto_struct!($body { $($fnam: $ftyp),* });)*
467    };
468}
469
470#[macro_export]
471macro_rules! strip_plus {
472    (+ $($rest: tt)*) => {
473        $($rest)*
474    }
475}
476
477#[macro_export]
478macro_rules! proto_enum_deserialize_variant {
479    ($data: ident, $ty: ident :: $nam: ident ($bod: ty)) => {
480        Ok(<$bod>::mc_deserialize($data)?.map(move |body| $ty::$nam(body)))
481    };
482    ($data: ident, $ty: ident :: $nam: ident) => {
483        Deserialized::ok($ty::$nam, $data)
484    };
485}
486
487#[macro_export]
488macro_rules! instead_of_ident {
489    ($ident: tt, $replacement: tt) => {
490        $replacement
491    }
492}
493
494#[macro_export]
495macro_rules! proto_enum_with_type {
496    ($typ: ty, $typname: ident, $(($bval: literal, $nam: ident $(($bod: ty))?)),*) => {
497        $crate::as_item! {
498            #[derive(PartialEq, Clone, Debug)]
499            pub enum $typname {
500                $($nam $(($bod))?),*
501            }
502        }
503
504        impl Serialize for $typname {
505            fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
506                let id_to_serialize: $typ = match self {
507                    $($typname::$nam$((instead_of_ident!($bod, _)))? => $bval),*
508                }.into();
509                to.serialize_other(&id_to_serialize)?;
510                self.serialize_body(to)
511            }
512        }
513
514        impl Deserialize for $typname {
515            fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
516                <$typ>::mc_deserialize(data)?.and_then(move |id, rest| {
517                    Self::deserialize_with_id(id, rest)
518                })
519            }
520        }
521
522        impl $typname {
523            pub const fn variant_count() -> usize {
524                crate::strip_plus!($(+ crate::instead_of_ident!($bval, 1))+)
525            }
526
527            pub fn deserialize_with_id<'a>(id: $typ, data: &'a[u8]) -> DeserializeResult<'a, Self> {
528                match id.into() {
529                    $($bval => proto_enum_deserialize_variant!(data, $typname::$nam $(($bod))?)),*,
530                    other => {
531                        return Err(DeserializeErr::CannotUnderstandValue(alloc::format!("invalid {} {:?}", stringify!($typname), other)))
532                    }
533                }
534            }
535
536            pub fn name(&self) -> &str {
537                match self {
538                    $($typname::$nam$((instead_of_ident!($bod, _)))? => stringify!($nam)),*
539                }
540            }
541
542            pub fn id(&self) -> $typ {
543                match self {
544                    $($typname::$nam$((instead_of_ident!($bod, _)))? => $bval.into()),*
545                }
546            }
547
548            #[allow(unused_variables)]
549            pub fn serialize_body<S: Serializer>(&self, to: &mut S) -> SerializeResult {
550                match &self {
551                    $($typname::$nam$((instead_of_ident!($bod, bod)))? => {
552                        $(to.serialize_other(instead_of_ident!($bod, bod))?;)?
553                        Ok(())
554                    }),*
555                }
556            }
557        }
558
559        #[cfg(all(test, feature = "std"))]
560        impl TestRandom for $typname {
561            fn test_gen_random() -> Self {
562                let mut rng = rand::thread_rng();
563                use rand::distributions::Distribution;
564                let distr = rand::distributions::Uniform::new(1, Self::variant_count() + 1);
565                let mut idx: usize = distr.sample(&mut rng);
566                $(
567                    idx -= 1;
568                    if idx == 0 {
569                        return $typname::$nam$((<$bod>::test_gen_random()))?;
570                    }
571                )+
572                panic!("cannot generate random {}", stringify!($typname));
573            }
574        }
575    }
576}
577
578#[macro_export]
579macro_rules! proto_byte_enum {
580    ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => {
581        proto_enum_with_type!(u8, $typname, $(($bval, $nam $(($bod))?)),*);
582    }
583}
584
585#[macro_export]
586macro_rules! proto_varint_enum {
587    ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => {
588        proto_enum_with_type!(VarInt, $typname, $(($bval, $nam $(($bod))?)),*);
589    }
590}
591
592#[macro_export]
593macro_rules! proto_int_enum {
594    ($typname: ident, $($bval: literal :: $nam: ident $(($bod: ty))?),*) => {
595        proto_enum_with_type!(i32, $typname, $(($bval, $nam $(($bod))?)),*);
596    }
597}
598
599#[macro_export]
600macro_rules! proto_str_enum {
601    ($typname: ident, $($sval: literal :: $nam: ident $(($bod: ident))?),*) => {
602        crate::as_item! {
603            #[derive(PartialEq, Clone, Debug)]
604            pub enum $typname {
605                $($nam $(($bod))?),*
606            }
607        }
608
609        impl Serialize for $typname {
610            fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
611                let name = self.name().to_owned();
612                to.serialize_other(&name)?;
613                self.serialize_body(to)
614            }
615        }
616
617        impl Deserialize for $typname {
618            fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
619                String::mc_deserialize(data)?.and_then(move |name, rest| {
620                    Self::deserialize_with_id(name.as_str(), rest)
621                })
622            }
623        }
624
625        impl $typname {
626            pub const fn variant_count() -> usize {
627                crate::strip_plus!($(+ crate::instead_of_ident!($sval, 1))+)
628            }
629
630            pub fn name(&self) -> &str {
631                match self {
632                    $($typname::$nam$((instead_of_ident!($bod, _)))? => $sval),+,
633                }
634            }
635
636            pub fn id(&self) -> String {
637                self.name().to_owned()
638            }
639
640            pub fn deserialize_with_id<'a>(name: &str, data: &'a[u8]) -> DeserializeResult<'a, Self> {
641                match name {
642                    $($sval => proto_enum_deserialize_variant!(data, $typname::$nam $(($bod))?)),*,
643                    other => Err(DeserializeErr::CannotUnderstandValue(alloc::format!("invalid {} ident '{}'", stringify!($typname), other)))
644                }
645            }
646
647            #[allow(unused_variables)]
648            pub fn serialize_body<S: Serializer>(&self, to: &mut S) -> SerializeResult {
649                match &self {
650                    $($typname::$nam$((instead_of_ident!($bod, bod)))? => {
651                        $(to.serialize_other(instead_of_ident!($bod, bod))?;)?
652                        Ok(())
653                    }),*
654                }
655            }
656        }
657
658        impl From<&$typname> for String {
659            fn from(arg: &$typname) -> Self {
660                arg.name().to_owned()
661            }
662        }
663
664        impl From<$typname> for String {
665            fn from(arg: $typname) -> Self {
666                arg.name().to_owned()
667            }
668        }
669
670        #[cfg(all(test, feature = "std"))]
671        impl TestRandom for $typname {
672            fn test_gen_random() -> Self {
673                let mut rng = rand::thread_rng();
674                use rand::distributions::Distribution;
675                let distr = rand::distributions::Uniform::new(1, Self::variant_count() + 1);
676                let mut idx: usize = distr.sample(&mut rng);
677                $(
678                    idx -= 1;
679                    if idx == 0 {
680                        return $typname::$nam$(($bod::test_gen_random()))?;
681                    }
682                )+
683                panic!("cannot generate random {}", stringify!($typname));
684            }
685        }
686    }
687}
688
689#[macro_export]
690macro_rules! proto_byte_flag {
691    ($typname: ident, $($bval: literal :: $isnam: ident $setnam: ident),*) => {
692        #[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
693        pub struct $typname(pub u8);
694
695        impl $typname {
696            $(pub fn $isnam(&self) -> bool {
697                self.0 & $bval != 0
698            }
699
700            pub fn $setnam(&mut self, value: bool) {
701                if value {
702                    self.0 |= $bval;
703                } else {
704                    self.0 ^= $bval & self.0;
705                }
706            })+
707        }
708
709        impl Serialize for $typname {
710            fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
711                to.serialize_byte(self.0)
712            }
713        }
714
715        impl Deserialize for $typname {
716            fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
717                Ok(u8::mc_deserialize(data)?.map(move |b| $typname(b)))
718            }
719        }
720
721        #[cfg(all(test, feature = "std"))]
722        impl TestRandom for $typname {
723            fn test_gen_random() -> Self {
724                let mut out = <$typname>::default();
725                $(
726                    out.$setnam(rand::random::<bool>());
727                )+
728                out
729            }
730        }
731    }
732}