rak_rs/protocol/packet/mod.rs
1//! This module contains all the packets that are used by the RakNet protocol.
2//! This module is split into two submodules:
3//! - [`offline`]: Any packet that is not sent within a [`Frame`].
4//! - [`online`]: Any packet considered to be online, which is sent within a [`Frame`].
5//!
6//! [`offline`]: crate::protocol::packet::offline
7//! [`online`]: crate::protocol::packet::online
8// /// Handlers for both online & offline packets!
9// /// This is used by the connection struct to handle packets.
10// pub(crate) mod handler;
11
12pub mod offline;
13pub mod online;
14
15use binary_util::interfaces::{Reader, Writer};
16
17use self::offline::OfflinePacket;
18use self::online::OnlinePacket;
19
20/// A wrapper or helper for both online and offline packets.
21/// This allows for a single type to be read with `Reader` and written with `Writer`,
22/// traits provided by `binary_util`.
23///
24/// All packets sent are wrapped in this type, and can be unwrapped with the `get_offline` or `get_online`
25#[derive(Debug, Clone)]
26pub enum RakPacket {
27 Offline(OfflinePacket),
28 Online(OnlinePacket),
29}
30
31impl RakPacket {
32 pub fn is_online(&self) -> bool {
33 match self {
34 RakPacket::Online(_) => true,
35 _ => false,
36 }
37 }
38
39 pub fn get_offline(&self) -> Option<&OfflinePacket> {
40 match self {
41 RakPacket::Offline(packet) => Some(packet),
42 _ => None,
43 }
44 }
45
46 pub fn get_online(&self) -> Option<&OnlinePacket> {
47 match self {
48 RakPacket::Online(packet) => Some(packet),
49 _ => None,
50 }
51 }
52}
53
54impl Writer for RakPacket {
55 fn write(&self, buf: &mut binary_util::io::ByteWriter) -> Result<(), std::io::Error> {
56 match self {
57 RakPacket::Offline(packet) => packet.write(buf),
58 RakPacket::Online(packet) => packet.write(buf),
59 }
60 }
61}
62
63impl Reader<RakPacket> for RakPacket {
64 fn read(buf: &mut binary_util::ByteReader) -> Result<RakPacket, std::io::Error> {
65 if let Ok(packet) = OfflinePacket::read(buf) {
66 return Ok(RakPacket::Offline(packet));
67 }
68 if let Ok(packet) = OnlinePacket::read(buf) {
69 return Ok(RakPacket::Online(packet));
70 }
71
72 Err(std::io::Error::new(
73 std::io::ErrorKind::InvalidData,
74 "Invalid packet",
75 ))
76 }
77}
78
79impl From<OfflinePacket> for RakPacket {
80 fn from(packet: OfflinePacket) -> Self {
81 RakPacket::Offline(packet)
82 }
83}
84
85impl From<OnlinePacket> for RakPacket {
86 fn from(packet: OnlinePacket) -> Self {
87 RakPacket::Online(packet)
88 }
89}
90
91impl From<RakPacket> for OnlinePacket {
92 fn from(packet: RakPacket) -> Self {
93 match packet {
94 RakPacket::Online(packet) => packet,
95 _ => panic!("Invalid packet conversion"),
96 }
97 }
98}
99
100impl From<RakPacket> for OfflinePacket {
101 fn from(packet: RakPacket) -> Self {
102 match packet {
103 RakPacket::Offline(packet) => packet,
104 _ => panic!("Invalid packet conversion"),
105 }
106 }
107}
108
109/// A utility macro that adds the implementation for any `OnlinePacket(Pk)` where
110/// `Pk` can be converted to `RakPacket`, `OnlinePacket` or `OfflinePacket`
111/// and vice versa.
112///
113/// For example, we want unconnected pong to be unwrapped, we can do this without
114/// a match statement like this:
115/// ```rust ignore
116/// use raknet::packet::RakPacket;
117/// use raknet::packet::online::OnlinePacket;
118/// use raknet::packet::online::UnconnectedPing;
119/// let some_packet = RakPacket::from(&source)?;
120/// let connected_ping: UnconnectedPing = some_packet.into();
121/// ```
122///
123/// This macro also allows for converting any `OnlinePacket(Pk)` to a `RakPacket`, where `Pk` can
124/// be directly converted into a packet. For example:
125/// ```rust ignore
126/// use raknet::packet::Packet;
127/// use raknet::packet::online::OnlinePacket;
128/// use raknet::packet::online::UnconnectedPong;
129///
130/// let packet: Packet = UnconnectedPong {
131/// magic: Magic::new(),
132/// timestamp: SystemTime::now(),
133/// client_id: -129
134/// }.into();
135/// ```
136///
137/// The macro can be expressed in the following way:
138/// ```rust ignore
139/// register_packets! {
140/// Online is OnlinePacket,
141/// UnconnectedPing,
142/// // etc...
143/// }
144/// ```
145#[macro_export]
146macro_rules! register_packets {
147 ($name: ident is $kind: ident, $($packet: ident),*) => {
148 $(
149 impl From<$packet> for $kind {
150 fn from(packet: $packet) -> Self {
151 $kind::$packet(packet)
152 }
153 }
154
155 impl From<$packet> for RakPacket {
156 fn from(packet: $packet) -> Self {
157 $kind::$packet(packet).into()
158 }
159 }
160
161 impl From<$kind> for $packet {
162 fn from(packet: $kind) -> Self {
163 match packet {
164 $kind::$packet(packet) => packet.into(),
165 _ => panic!("Invalid packet conversion"),
166 }
167 }
168 }
169
170 impl From<RakPacket> for $packet {
171 fn from(packet: RakPacket) -> Self {
172 match packet {
173 RakPacket::$name(packet) => packet.into(),
174 _ => panic!("Invalid packet conversion"),
175 }
176 }
177 }
178 )*
179 };
180}