1#![allow(dead_code)]
2#![allow(non_camel_case_types)]
3#![allow(unused_parens)]
4#![allow(unused_mut)]
5
6#[cfg(test)]
7mod tests;
8
9pub mod client;
11pub mod server;
13
14#[cfg(feature = "derive")]
15pub use bancho_packets_derive::*;
16
17use enum_primitive_derive::Primitive;
18use std::{
19 borrow::Cow,
20 convert::TryInto,
21 ops::{Deref, DerefMut},
22};
23
24pub type CowStr<'a> = Cow<'a, str>;
25
26pub trait BanchoPacket {
27 const ID: PacketId;
28
29 fn into_packet_data(self) -> Vec<u8>;
30}
31
32pub const BANCHO_PACKET_HEADER_LENGTH: usize = 7;
39
40pub const EMPTY_STRING_PACKET: &[u8; 2] = b"\x0b\x00";
41
42#[cfg(feature = "serde")]
43use serde::{Deserialize, Serialize};
44
45#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46#[derive(Debug, Clone)]
47pub struct Packet<'a> {
49 pub id: PacketId,
50 pub payload: Option<&'a [u8]>,
51}
52
53impl<'a> Packet<'a> {
54 pub fn new(id: PacketId) -> Self {
55 Self { id, payload: None }
56 }
57
58 pub fn with_payload(id: PacketId, payload: Option<&'a [u8]>) -> Self {
59 Self { id, payload }
60 }
61
62 pub fn with_raw_id_and_payload(
63 raw_id: u8,
64 payload: Option<&'a [u8]>,
65 ) -> Self {
66 Self { id: PacketId::new(raw_id), payload }
67 }
68}
69
70impl<'a> std::fmt::Display for Packet<'a> {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 f.write_fmt(format_args!(
73 "Packet {{ {}, payload: {} }}",
74 self.id,
75 self.payload.is_some()
76 ))
77 }
78}
79
80#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
81#[derive(Debug, Clone)]
82pub struct PacketHeader {
84 pub id: PacketId,
85 pub payload_length: u32,
86}
87
88#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
89#[derive(Debug, Clone)]
90pub enum LoginResult {
93 Success(i32),
94 Failed(LoginFailedReason),
95}
96
97impl Default for LoginResult {
98 fn default() -> Self {
99 Self::Failed(Default::default())
100 }
101}
102
103impl From<i32> for LoginResult {
104 fn from(val: i32) -> Self {
105 Self::Success(val)
106 }
107}
108
109impl From<LoginFailedReason> for LoginResult {
110 fn from(val: LoginFailedReason) -> Self {
111 Self::Failed(val)
112 }
113}
114
115#[rustfmt::skip]
116#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
117#[derive(
118 Debug,
119 Default,
120 Clone,
121 Copy,
122 PartialEq,
123 Eq,
124 PartialOrd,
125 Ord,
126 Hash
127)]
128#[repr(i32)]
129pub enum LoginFailedReason {
131 #[default]
132 InvalidCredentials = -1,
133 OutdatedClient = -2,
134 UserBanned = -3,
135 MultiaccountDetected = -4,
136 ServerError = -5,
137 CuttingEdgeMultiplayer = -6,
138 AccountPasswordRest = -7,
139 VerificationRequired = -8,
140}
141
142#[rustfmt::skip]
143#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
144#[derive(
145 Debug,
146 Default,
147 Clone,
148 Copy,
149 PartialEq,
150 Eq,
151 PartialOrd,
152 Ord,
153 Hash,
154 Primitive
155)]
156#[repr(u8)]
157pub enum PacketId {
159 OSU_USER_CHANGE_ACTION = 0,
160 OSU_SEND_PUBLIC_MESSAGE = 1,
161 OSU_USER_LOGOUT = 2,
162 OSU_USER_REQUEST_STATUS_UPDATE = 3,
163 OSU_PING = 4,
164 BANCHO_USER_LOGIN_REPLY = 5,
165 BANCHO_SEND_MESSAGE = 7,
166 BANCHO_PONG = 8,
167 BANCHO_HANDLE_IRC_CHANGE_USERNAME = 9,
168 BANCHO_HANDLE_IRC_QUIT = 10,
169 BANCHO_USER_STATS = 11,
170 BANCHO_USER_LOGOUT = 12,
171 BANCHO_SPECTATOR_JOINED = 13,
172 BANCHO_SPECTATOR_LEFT = 14,
173 BANCHO_SPECTATE_FRAMES = 15,
174 OSU_SPECTATE_START = 16,
175 OSU_SPECTATE_STOP = 17,
176 OSU_SPECTATE_FRAMES = 18,
177 BANCHO_VERSION_UPDATE = 19,
178 OSU_ERROR_REPORT = 20,
179 OSU_SPECTATE_CANT = 21,
180 BANCHO_SPECTATOR_CANT_SPECTATE = 22,
181 BANCHO_GET_ATTENTION = 23,
182 BANCHO_NOTIFICATION = 24,
183 OSU_SEND_PRIVATE_MESSAGE = 25,
184 BANCHO_UPDATE_MATCH = 26,
185 BANCHO_NEW_MATCH = 27,
186 BANCHO_DISBAND_MATCH = 28,
187 OSU_USER_PART_LOBBY = 29,
188 OSU_USER_JOIN_LOBBY = 30,
189 OSU_USER_CREATE_MATCH = 31,
190 OSU_USER_JOIN_MATCH = 32,
191 OSU_USER_PART_MATCH = 33,
192 BANCHO_TOGGLE_BLOCK_NON_FRIEND_DMS = 34,
193 BANCHO_MATCH_JOIN_SUCCESS = 36,
194 BANCHO_MATCH_JOIN_FAIL = 37,
195 OSU_MATCH_CHANGE_SLOT = 38,
196 OSU_USER_MATCH_READY = 39,
197 OSU_MATCH_LOCK = 40,
198 OSU_MATCH_CHANGE_SETTINGS = 41,
199 BANCHO_FELLOW_SPECTATOR_JOINED = 42,
200 BANCHO_FELLOW_SPECTATOR_LEFT = 43,
201 OSU_MATCH_START = 44,
202 BANCHO_ALL_PLAYERS_LOADED = 45,
203 BANCHO_MATCH_START = 46,
204 OSU_MATCH_SCORE_UPDATE = 47,
205 BANCHO_MATCH_SCORE_UPDATE = 48,
206 OSU_MATCH_COMPLETE = 49,
207 BANCHO_MATCH_TRANSFER_HOST = 50,
208 OSU_MATCH_CHANGE_MODS = 51,
209 OSU_MATCH_LOAD_COMPLETE = 52,
210 BANCHO_MATCH_ALL_PLAYERS_LOADED = 53,
211 OSU_MATCH_NO_BEATMAP = 54,
212 OSU_MATCH_NOT_READY = 55,
213 OSU_MATCH_FAILED = 56,
214 BANCHO_MATCH_PLAYER_FAILED = 57,
215 BANCHO_MATCH_COMPLETE = 58,
216 OSU_MATCH_HAS_BEATMAP = 59,
217 OSU_MATCH_SKIP_REQUEST = 60,
218 BANCHO_MATCH_SKIP = 61,
219 BANCHO_UNAUTHORIZED = 62,
220 OSU_USER_CHANNEL_JOIN = 63,
221 BANCHO_CHANNEL_JOIN_SUCCESS = 64,
222 BANCHO_CHANNEL_INFO = 65,
223 BANCHO_CHANNEL_KICK = 66,
224 BANCHO_CHANNEL_AUTO_JOIN = 67,
225 OSU_BEATMAP_INFO_REQUEST = 68,
226 BANCHO_BEATMAP_INFO_REPLY = 69,
227 OSU_MATCH_TRANSFER_HOST = 70,
228 BANCHO_PRIVILEGES = 71,
229 BANCHO_FRIENDS_LIST = 72,
230 OSU_USER_FRIEND_ADD = 73,
231 OSU_USER_FRIEND_REMOVE = 74,
232 BANCHO_PROTOCOL_VERSION = 75,
233 BANCHO_MAIN_MENU_ICON = 76,
234 OSU_MATCH_CHANGE_TEAM = 77,
235 OSU_USER_CHANNEL_PART = 78,
236 OSU_USER_RECEIVE_UPDATES = 79,
237 BANCHO_MONITOR = 80,
238 BANCHO_MATCH_PLAYER_SKIPPED = 81,
239 OSU_USER_SET_AWAY_MESSAGE = 82,
240 BANCHO_USER_PRESENCE = 83,
241 OSU_IRC_ONLY = 84,
242 OSU_USER_STATS_REQUEST = 85,
243 BANCHO_RESTART = 86,
244 OSU_MATCH_INVITE = 87,
245 BANCHO_MATCH_INVITE = 88,
246 BANCHO_CHANNEL_INFO_END = 89,
247 OSU_MATCH_CHANGE_PASSWORD = 90,
248 BANCHO_MATCH_CHANGE_PASSWORD = 91,
249 BANCHO_SILENCE_END = 92,
250 OSU_TOURNAMENT_MATCH_INFO_REQUEST = 93,
251 BANCHO_USER_SILENCED = 94,
252 BANCHO_USER_PRESENCE_SINGLE = 95,
253 BANCHO_USER_PRESENCE_BUNDLE = 96,
254 OSU_USER_PRESENCE_REQUEST = 97,
255 OSU_USER_PRESENCE_REQUEST_ALL = 98,
256 OSU_USER_TOGGLE_BLOCK_NON_FRIEND_DMS = 99,
257 BANCHO_USER_DM_BLOCKED = 100,
258 BANCHO_TARGET_IS_SILENCED = 101,
259 BANCHO_VERSION_UPDATE_FORCED = 102,
260 BANCHO_SWITCH_SERVER = 103,
261 BANCHO_ACCOUNT_RESTRICTED = 104,
262 BANCHO_RTX = 105,
263 BANCHO_MATCH_ABORT = 106,
264 BANCHO_SWITCH_TOURNAMENT_SERVER = 107,
265 OSU_TOURNAMENT_JOIN_MATCH_CHANNEL = 108,
266 OSU_TOURNAMENT_LEAVE_MATCH_CHANNEL = 109,
267 #[default]
268 OSU_UNKNOWN_PACKET = 255,
269}
270
271impl std::fmt::Display for PacketId {
272 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273 f.write_fmt(format_args!("{:?}", self))
274 }
275}
276
277impl PacketId {
278 pub fn new(value: u8) -> Self {
279 Self::try_from(value).unwrap_or_default()
280 }
281}
282
283#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
284#[derive(Debug, Clone, ReadPacket, Default)]
285pub struct BanchoMessage {
287 pub sender: String,
288 pub content: String,
289 pub target: String,
290 pub sender_id: i32,
291}
292
293#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
294#[derive(Debug, Clone, PacketLength, Default)]
295pub struct MatchData {
297 pub match_id: i32,
298 pub in_progress: bool,
299 pub match_type: i8,
300 pub play_mods: u32,
301 pub match_name: String,
302 #[length(self.password.as_ref().map(|pw| pw.packet_len()).unwrap_or(2))]
303 pub password: Option<String>,
304 pub beatmap_name: String,
305 pub beatmap_id: i32,
306 pub beatmap_md5: String,
307 pub slot_status: Vec<u8>,
308 pub slot_teams: Vec<u8>,
309 pub slot_players: Vec<i32>,
310 pub host_player_id: i32,
311 pub match_game_mode: u8,
312 pub win_condition: u8,
313 pub team_type: u8,
314 pub freemods: bool,
315 pub player_mods: Vec<i32>,
316 pub match_seed: i32,
317}
318
319#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
320#[derive(Debug, Clone, PacketLength, Default)]
321pub struct MatchUpdate {
322 pub data: MatchData,
323 pub send_password: bool,
324}
325
326impl Deref for MatchUpdate {
327 type Target = MatchData;
328
329 #[inline]
330 fn deref(&self) -> &Self::Target {
331 &self.data
332 }
333}
334
335impl DerefMut for MatchUpdate {
336 #[inline]
337 fn deref_mut(&mut self) -> &mut Self::Target {
338 &mut self.data
339 }
340}
341
342#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
343#[derive(Debug, Clone, ReadPacket, WritePacket, PacketLength, Default)]
344pub struct ScoreFrame {
346 pub timestamp: i32,
347 pub id: u8,
348 pub n300: u16,
349 pub n100: u16,
350 pub n50: u16,
351 pub geki: u16,
352 pub katu: u16,
353 pub miss: u16,
354 pub score: i32,
355 pub combo: u16,
356 pub max_combo: u16,
357 pub perfect: bool,
358 pub hp: u8,
359 pub tag_byte: u8,
360 pub score_v2: bool,
361}
362
363#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
364#[derive(Debug, Clone, ReadPacket, WritePacket, PacketLength, Default)]
365pub struct ClientChangeAction {
366 pub online_status: u8,
367 pub description: String,
368 pub beatmap_md5: String,
369 pub mods: u32,
370 pub mode: u8,
371 pub beatmap_id: i32,
372}
373
374#[derive(Debug, Clone)]
375pub struct PayloadReader<'a> {
403 pub(crate) payload: &'a [u8],
404 pub(crate) index: usize,
405}
406
407impl<'a> PayloadReader<'a> {
408 #[inline]
409 pub fn new(payload: &'a [u8]) -> Self {
410 PayloadReader { payload, index: 0 }
411 }
412
413 #[inline]
414 pub fn read<T>(&mut self) -> Option<T>
417 where
418 T: BanchoPacketRead<T>,
419 {
420 T::read(self)
421 }
422
423 #[inline]
424 pub fn index(&self) -> usize {
425 self.index
426 }
427
428 #[inline]
429 pub fn payload(&self) -> &'a [u8] {
430 self.payload
431 }
432
433 #[inline]
434 pub fn reset(&mut self) {
436 self.index = 0
437 }
438
439 #[inline]
440 pub(crate) fn increase_index(&mut self, offset: usize) -> usize {
441 self.index += offset;
442 self.index
443 }
444
445 #[inline]
446 pub(crate) fn decrease_index(&mut self, offset: usize) -> usize {
447 self.index -= offset;
448 self.index
449 }
450
451 #[inline]
452 pub(crate) fn next_with_length(&mut self, length: usize) -> Option<&[u8]> {
453 self.index += length;
454 self.payload.get(self.index - length..self.index)
455 }
456
457 #[inline]
458 pub(crate) fn next_with_length_type<Len: Sized>(
459 &mut self,
460 ) -> Option<&[u8]> {
461 self.next_with_length(std::mem::size_of::<Len>())
462 }
463
464 #[inline]
465 pub(crate) fn read_uleb128(&mut self) -> Option<u32> {
466 let (val, length) = uleb128_to_u32(self.payload.get(self.index..)?)?;
467 self.index += length;
468 Some(val)
469 }
470}
471
472#[derive(Debug, Clone)]
473pub struct PacketReader<'a> {
516 buf: &'a [u8],
517 ptr: usize,
518}
519
520impl<'a> PacketReader<'a> {
521 #[inline]
522 pub fn new(buf: &'a [u8]) -> Self {
524 PacketReader { buf, ptr: 0 }
525 }
526
527 #[inline]
528 pub fn index(&self) -> usize {
529 self.ptr
530 }
531
532 #[inline]
533 pub fn buffer(&self) -> &'a [u8] {
534 self.buf
535 }
536
537 #[inline]
538 pub fn reset(&mut self) {
540 self.ptr = 0;
541 }
542
543 #[inline]
544 pub fn parse_header(header: &[u8]) -> Option<PacketHeader> {
546 let packet_id = *header.first()?;
547 Some(PacketHeader {
548 id: PacketId::new(packet_id),
549 payload_length: u32::from_le_bytes(
550 header[3..BANCHO_PACKET_HEADER_LENGTH].try_into().ok()?,
551 ),
552 })
553 }
554}
555
556impl<'a> Iterator for PacketReader<'a> {
557 type Item = Packet<'a>;
558
559 fn next(&mut self) -> Option<Self::Item> {
560 if (self.buf.len() - self.ptr) < BANCHO_PACKET_HEADER_LENGTH {
561 return None;
562 }
563 let header =
566 &self.buf[self.ptr..self.ptr + BANCHO_PACKET_HEADER_LENGTH];
567 self.ptr += BANCHO_PACKET_HEADER_LENGTH;
568
569 let PacketHeader { id, payload_length } =
571 PacketReader::parse_header(header)?;
572
573 let payload = if payload_length == 0 {
575 None
576 } else {
577 let next_payload_length = payload_length as usize;
578
579 self.ptr += next_payload_length;
580 self.buf.get(self.ptr - next_payload_length..self.ptr)
581 };
582
583 Some(Packet { id, payload })
584 }
585}
586
587#[derive(Debug, Clone)]
588pub struct PacketBuilder {
607 buffer: Vec<u8>,
608}
609
610impl Default for PacketBuilder {
611 fn default() -> Self {
612 Self::new()
613 }
614}
615
616impl Deref for PacketBuilder {
617 type Target = Vec<u8>;
618
619 fn deref(&self) -> &Self::Target {
620 &self.buffer
621 }
622}
623
624impl DerefMut for PacketBuilder {
625 fn deref_mut(&mut self) -> &mut Self::Target {
626 &mut self.buffer
627 }
628}
629
630impl PacketBuilder {
631 #[inline]
632 pub fn new() -> Self {
634 Self { buffer: Vec::new() }
635 }
636
637 #[inline]
638 pub fn with_capacity(capacity: usize) -> Self {
640 Self { buffer: Vec::with_capacity(capacity) }
641 }
642
643 #[inline]
644 pub fn with_packet_id(packet_id: PacketId) -> Self {
646 Self { buffer: new_empty_packet(packet_id) }
647 }
648
649 #[inline]
650 pub fn build(self) -> Vec<u8> {
652 self.buffer
653 }
654
655 #[inline]
656 pub fn buffer(&self) -> &Vec<u8> {
657 &self.buffer
658 }
659
660 #[inline]
661 pub fn buffer_mut(&mut self) -> &mut Vec<u8> {
662 &mut self.buffer
663 }
664
665 #[inline]
666 pub fn from_batch<P, I>(packets: P) -> Self
668 where
669 I: IntoIterator<Item = u8>,
670 P: IntoIterator<Item = I>,
671 {
672 Self::new().add_batch(packets)
673 }
674
675 #[inline]
676 pub fn add_batch<P, I>(mut self, packets: P) -> Self
678 where
679 I: IntoIterator<Item = u8>,
680 P: IntoIterator<Item = I>,
681 {
682 self.add_batch_ref(packets);
683 self
684 }
685
686 #[inline]
687 pub fn add_batch_ref<P, I>(&mut self, packets: P) -> &Self
689 where
690 I: IntoIterator<Item = u8>,
691 P: IntoIterator<Item = I>,
692 {
693 for p in packets {
694 self.buffer.extend(p)
695 }
696 self
697 }
698
699 #[allow(clippy::should_implement_trait)]
700 #[inline]
701 pub fn add<P>(mut self, packet: P) -> Self
703 where
704 P: IntoIterator<Item = u8>,
705 {
706 self.add_ref(packet);
707 self
708 }
709
710 #[inline]
711 pub fn add_ref<P>(&mut self, packet: P) -> &Self
713 where
714 P: IntoIterator<Item = u8>,
715 {
716 self.buffer.extend(packet);
717 self
718 }
719}
720
721impl From<Vec<u8>> for PacketBuilder {
722 #[inline]
723 fn from(buffer: Vec<u8>) -> Self {
724 Self { buffer }
725 }
726}
727
728pub trait BanchoPacketRead<T> {
731 fn read(reader: &mut PayloadReader) -> Option<T>;
732}
733
734impl BanchoPacketRead<String> for String {
735 #[inline]
736 fn read(reader: &mut PayloadReader) -> Option<String> {
737 if reader.payload.get(reader.index())? != &0xb {
738 return None;
739 }
740 reader.increase_index(1);
741 let data_length = reader.read_uleb128()? as usize;
742
743 let cur = reader.index;
744 reader.increase_index(data_length);
745 let data = reader.payload.get(cur..reader.index)?;
746
747 Some(std::str::from_utf8(data).ok()?.into())
748 }
749}
750
751impl BanchoPacketRead<bool> for bool {
752 #[inline]
753 fn read(reader: &mut PayloadReader) -> Option<bool> {
754 Some(reader.read::<i8>()? == 1)
755 }
756}
757
758macro_rules! impl_number {
759 ($($t:ty),+) => {
760 $(impl BanchoPacketRead<$t> for $t {
761 #[inline]
762 fn read(reader: &mut PayloadReader) -> Option<$t> {
763 Some(<$t>::from_le_bytes(
764 reader.next_with_length_type::<$t>()?.try_into().ok()?,
765 ))
766 }
767 })+
768 };
769}
770
771impl_number!(i8, u8, i16, u16, i32, u32, i64, u64);
772
773macro_rules! impl_read_number_array {
774 ($($t:ty),+) => {
775 $(impl BanchoPacketRead<Vec<$t>> for Vec<$t> {
776 #[inline]
777 fn read(reader: &mut PayloadReader) -> Option<Vec<$t>> {
778 let length_data = reader.next_with_length_type::<i16>()?;
779 let int_count = <i16>::from_le_bytes(length_data.try_into().ok()?) as usize;
780
781 let mut data = Vec::with_capacity(int_count);
782 for _ in 0..int_count {
783 data.push(<$t>::from_le_bytes(reader.next_with_length_type::<i32>()?.try_into().ok()?));
784 }
785 Some(data)
786 }
787 })+
788 };
789}
790
791impl_read_number_array!(i8, u8, i16, u16, i32, u32, i64, u64);
792
793pub trait BanchoPacketWrite {
796 fn write_into_buf(self, buf: &mut Vec<u8>);
799
800 #[inline]
801 fn into_packet(self) -> Vec<u8>
803 where
804 Self: Sized,
805 {
806 let mut buf = Vec::new();
807 self.write_into_buf(&mut buf);
808 buf
809 }
810}
811
812impl BanchoPacketWrite for Cow<'_, str> {
813 #[inline]
814 fn write_into_buf(self, buf: &mut Vec<u8>) {
815 match self {
816 Cow::Borrowed(s) => s.write_into_buf(buf),
817 Cow::Owned(s) => s.write_into_buf(buf),
818 }
819 }
820}
821
822impl BanchoPacketWrite for &str {
823 #[inline]
824 fn write_into_buf(self, buf: &mut Vec<u8>) {
825 let byte_length = self.len();
826 if byte_length > 0 {
827 let (data, ptr) = u32_to_uleb128(byte_length as u32);
829 let length_uleb128 = &data[0..ptr];
830
831 let estimate_len = self.packet_len();
832 if buf.capacity() < estimate_len {
833 buf.reserve(estimate_len);
834 }
835
836 buf.push(0xb);
837 buf.extend(length_uleb128);
838 buf.extend(self.as_bytes());
839 } else {
840 buf.push(0);
841 }
842 }
843}
844
845impl BanchoPacketWrite for String {
846 #[inline]
847 fn write_into_buf(self, buf: &mut Vec<u8>) {
848 let byte_length = self.len();
849 if byte_length > 0 {
850 let (data, ptr) = u32_to_uleb128(byte_length as u32);
852 let length_uleb128 = &data[0..ptr];
853
854 let estimate_len = self.packet_len();
855 if buf.capacity() < estimate_len {
856 buf.reserve(estimate_len);
857 }
858
859 buf.push(0xb);
860 buf.extend(length_uleb128);
861 buf.extend(self.into_bytes());
862 } else {
863 buf.push(0);
864 }
865 }
866}
867
868impl BanchoPacketWrite for u8 {
869 #[inline]
870 fn write_into_buf(self, buf: &mut Vec<u8>) {
871 buf.push(self);
872 }
873}
874
875impl BanchoPacketWrite for &[u8] {
876 #[inline]
877 fn write_into_buf(self, buf: &mut Vec<u8>) {
878 buf.extend(self);
879 }
880}
881
882impl BanchoPacketWrite for Vec<u8> {
883 #[inline]
884 fn write_into_buf(self, buf: &mut Vec<u8>) {
885 buf.extend(self);
886 }
887}
888
889impl BanchoPacketWrite for bool {
890 #[inline]
891 fn write_into_buf(self, buf: &mut Vec<u8>) {
892 buf.push(if self { 1 } else { 0 });
893 }
894}
895
896macro_rules! impl_write_number {
897 ($($t:ty),+) => {
898 $(
899 impl BanchoPacketWrite for $t {
900 #[inline]
901 fn write_into_buf(self, buf: &mut Vec<u8>) {
902 buf.extend(self.to_le_bytes())
903 }
904 }
905
906 impl BanchoPacketLength for $t {
907 #[inline]
908 fn packet_len(&self) -> usize {
909 std::mem::size_of::<$t>()
910 }
911 }
912 )+
913 }
914}
915
916impl_write_number!(i8, u16, i16, i32, u32, i64, u64, f32, f64);
917
918macro_rules! impl_write_number_array {
919 ($($t:ty),+) => {$(
920 impl BanchoPacketWrite for &[$t] { impl_write_number_array!(@bancho_packet_write_inner $t); }
921 impl BanchoPacketWrite for Vec<$t> { impl_write_number_array!(@bancho_packet_write_inner $t); }
922
923 impl BanchoPacketLength for &[$t] { impl_write_number_array!(@bancho_packet_length_inner $t); }
924 impl BanchoPacketLength for Vec<$t> { impl_write_number_array!(@bancho_packet_length_inner $t); }
925 )+};
926 (@bancho_packet_write_inner $t:ty) => {
927 #[inline]
928 fn write_into_buf(self, buf: &mut Vec<u8>) {
929 let estimate_len = self.packet_len();
930 if buf.capacity() < estimate_len {
931 buf.reserve(estimate_len);
932 }
933
934 buf.extend((self.len() as u16).to_le_bytes());
935 for int in self {
936 buf.extend(int.to_le_bytes())
937 }
938 }
939 };
940 (@bancho_packet_length_inner $t:ty) => {
941 #[allow(clippy::manual_slice_size_calculation)]
942 #[inline]
943 fn packet_len(&self) -> usize {
944 std::mem::size_of::<u16>() + (std::mem::size_of::<$t>() * self.len())
945 }
946 }
947}
948
949impl_write_number_array!(i8, u16, i16, i32, u32, i64, u64, f32, f64);
950
951impl BanchoPacketWrite for LoginResult {
952 #[inline]
953 fn write_into_buf(self, buf: &mut Vec<u8>) {
954 match self {
955 LoginResult::Success(user_id) => user_id,
956 LoginResult::Failed(reason) => reason as i32,
957 }
958 .write_into_buf(buf)
959 }
960}
961
962impl BanchoPacketWrite for MatchUpdate {
963 #[inline]
964 fn write_into_buf(mut self, buf: &mut Vec<u8>) {
965 let MatchUpdate {
966 data:
967 MatchData {
968 match_id,
969 in_progress,
970 match_type,
971 play_mods,
972 match_name,
973 password,
974 beatmap_name,
975 beatmap_id,
976 beatmap_md5,
977 slot_status,
978 slot_teams,
979 slot_players,
980 host_player_id,
981 match_game_mode,
982 win_condition,
983 team_type,
984 freemods,
985 player_mods,
986 match_seed,
987 },
988 send_password,
989 } = self;
990
991 let raw_password = password
992 .map(|password| {
993 if send_password {
994 let mut raw = Vec::with_capacity(password.packet_len());
995 password.write_into_buf(&mut raw);
996 raw
997 } else {
998 EMPTY_STRING_PACKET.to_vec()
999 }
1000 })
1001 .unwrap_or(b"\x00".to_vec());
1002
1003 buf.extend(data!(
1004 match_id as u16,
1005 in_progress,
1006 match_type,
1007 play_mods,
1008 match_name,
1009 raw_password,
1010 beatmap_name,
1011 beatmap_id,
1012 beatmap_md5,
1013 slot_status,
1014 slot_teams,
1015 slot_players,
1016 host_player_id,
1017 match_game_mode,
1018 win_condition,
1019 team_type,
1020 freemods,
1021 player_mods,
1022 match_seed
1023 ));
1024 }
1025}
1026
1027impl BanchoPacketWrite for MatchData {
1028 #[inline]
1029 fn write_into_buf(self, buf: &mut Vec<u8>) {
1030 MatchUpdate { data: self, send_password: true }.write_into_buf(buf);
1031 }
1032}
1033
1034pub trait BanchoPacketLength {
1037 #[inline]
1038 fn packet_len(&self) -> usize {
1044 0
1045 }
1046}
1047
1048impl BanchoPacketLength for Cow<'_, str> {
1049 #[inline]
1050 fn packet_len(&self) -> usize {
1051 match self {
1052 Cow::Borrowed(s) => s.packet_len(),
1053 Cow::Owned(s) => s.packet_len(),
1054 }
1055 }
1056}
1057
1058impl BanchoPacketLength for &str {
1059 #[inline]
1060 fn packet_len(&self) -> usize {
1061 if !self.is_empty() {
1062 self.as_bytes().len() + 6
1063 } else {
1064 1
1065 }
1066 }
1067}
1068
1069impl BanchoPacketLength for String {
1070 #[inline]
1071 fn packet_len(&self) -> usize {
1072 if !self.is_empty() {
1073 self.as_bytes().len() + 6
1074 } else {
1075 1
1076 }
1077 }
1078}
1079
1080impl BanchoPacketLength for u8 {
1081 #[inline]
1082 fn packet_len(&self) -> usize {
1083 std::mem::size_of::<u8>()
1084 }
1085}
1086
1087impl BanchoPacketLength for &[u8] {
1088 #[inline]
1089 fn packet_len(&self) -> usize {
1090 self.len()
1091 }
1092}
1093
1094impl BanchoPacketLength for Vec<u8> {
1095 #[inline]
1096 fn packet_len(&self) -> usize {
1097 self.len()
1098 }
1099}
1100
1101impl BanchoPacketLength for bool {
1102 #[inline]
1103 fn packet_len(&self) -> usize {
1104 std::mem::size_of::<bool>()
1105 }
1106}
1107
1108impl BanchoPacketLength for LoginResult {
1109 #[inline]
1110 fn packet_len(&self) -> usize {
1111 std::mem::size_of::<i32>()
1112 }
1113}
1114
1115impl<T> BanchoPacketLength for Option<T>
1116where
1117 T: BanchoPacketLength,
1118{
1119 #[inline]
1120 fn packet_len(&self) -> usize {
1121 self.as_ref().map(|t| t.packet_len()).unwrap_or(0)
1122 }
1123}
1124
1125#[inline]
1126pub fn u32_to_uleb128(mut unsigned: u32) -> ([u8; 5], usize) {
1128 let mut data = [0, 0, 0, 0, 0];
1129 let mut ptr = 0;
1130
1131 loop {
1132 if unsigned < 0x80 {
1133 break;
1134 }
1135 data[ptr] = ((unsigned & 0x7f) | 0x80) as u8;
1136 ptr += 1;
1137 unsigned >>= 7;
1138 }
1139 data[ptr] = unsigned as u8;
1140
1141 (data, ptr + 1)
1142}
1143
1144#[inline]
1145pub fn uleb128_to_u32(uleb128_bytes: &[u8]) -> Option<(u32, usize)> {
1147 let (mut val, mut shift, mut index) = (0, 0, 0);
1148 loop {
1149 let byte = uleb128_bytes.get(index)?;
1150 index += 1;
1151 if (byte & 0x80) == 0 {
1152 val |= (*byte as u32) << shift;
1153 return Some((val, index));
1154 }
1155 val |= ((byte & 0x7f) as u32) << shift;
1156 shift += 7;
1157 }
1158}
1159
1160#[inline(always)]
1161pub fn new_empty_packet(packet_id: PacketId) -> Vec<u8> {
1173 vec![packet_id as u8, 0, 0, 0, 0, 0, 0]
1174}
1175
1176pub mod macros {
1178 #[macro_export]
1179 macro_rules! data {
1198 ($($item:expr$(,)*)*) => {
1199 {
1200 let mut estimate_capacity = 0;
1201 $(estimate_capacity += $item.packet_len();)*
1202
1203 let mut buf = Vec::<u8>::with_capacity(estimate_capacity);
1204 $($item.write_into_buf(&mut buf);)*
1205 buf
1206 }
1207 };
1208 (@capacity { $capacity:expr }, $($item:expr$(,)*)*) => {
1209 {
1210 let mut estimate_capacity = 0;
1211 $(estimate_capacity += $item.packet_len();)*
1212
1213 let mut buf = Vec::<u8>::with_capacity($capacity + estimate_capacity);
1214 $($item.write_into_buf(&mut buf);)*
1215 buf
1216 }
1217 }
1218 }
1219
1220 #[macro_export]
1221 macro_rules! packet {
1253 ($packet_id:expr $(,$data:expr)*) => {
1254 {
1255 let mut estimate_capacity = 0;
1256 $(estimate_capacity += $data.packet_len();)*
1257
1258 let mut packet = Vec::<u8>::with_capacity(estimate_capacity);
1259 packet.extend(&[$packet_id as u8, 0, 0, 0, 0, 0, 0]);
1260
1261 $($data.write_into_buf(&mut packet);)*
1262
1263 let packet_length_bytes =
1264 ((packet.len() - $crate::BANCHO_PACKET_HEADER_LENGTH) as i32)
1265 .to_le_bytes();
1266
1267 packet[3] = packet_length_bytes[0];
1269 packet[4] = packet_length_bytes[1];
1270 packet[5] = packet_length_bytes[2];
1271 packet[6] = packet_length_bytes[3];
1272
1273 packet
1274 }
1275 }
1276 }
1277
1278 #[macro_export]
1279 macro_rules! packet_struct {
1299 (
1300 $packet_id: expr,
1301 $(#[$struct_meta:meta])*
1302 $struct_name:ident $(< $($lifetimes:lifetime),* >)? {
1303 $(
1304 $(#[$field_meta:meta])*
1305 $field_name:ident: $field_type:ty$(,)*
1306 )*
1307 },
1308 fn $fn:ident ($self:ident) -> $ret:ty $body:block
1309 ) => {
1310 $(#[$struct_meta])*
1311 #[derive(Debug, Clone, Default)]
1312 pub struct $struct_name $(< $($lifetimes),* >)? {
1313 $(
1314 $(#[$field_meta])*
1315 pub $field_name: $field_type,
1316 )*
1317 }
1318
1319 impl $(< $($lifetimes),* >)? $crate::BanchoPacketLength for $struct_name $(< $($lifetimes),* >)? {
1320 #[inline]
1321 fn packet_len(&self) -> usize {
1322 let mut _len = $crate::BANCHO_PACKET_HEADER_LENGTH;
1323 $(_len += self.$field_name.packet_len();)*
1324 _len
1325 }
1326 }
1327
1328 impl$(< $($lifetimes),* >)? $struct_name$(< $($lifetimes),* >)? {
1329 #[allow(clippy::too_many_arguments)]
1330 #[inline]
1331 pub fn new(
1332 $($field_name: $field_type,)*
1333 ) -> Self {
1334 Self { $($field_name,)* }
1335 }
1336
1337 #[allow(clippy::too_many_arguments)]
1338 #[inline]
1339 pub fn pack(
1340 $($field_name: $field_type,)*
1341 ) -> Vec<u8> {
1342 $crate::BanchoPacket::into_packet_data(Self { $($field_name,)* })
1343 }
1344 }
1345
1346 impl$(< $($lifetimes),* >)? $crate::BanchoPacket for $struct_name$(< $($lifetimes),* >)? {
1347 const ID: $crate::PacketId = $packet_id;
1348
1349 #[inline]
1350 fn $fn ($self) -> $ret $body
1351 }
1352
1353 impl$(< $($lifetimes),* >)? IntoIterator for $struct_name$(< $($lifetimes),* >)? {
1354 type Item = u8;
1355
1356 type IntoIter = std::vec::IntoIter<u8>;
1357
1358 fn into_iter(self) -> Self::IntoIter {
1359 $crate::BanchoPacket::into_packet_data(self).into_iter()
1360 }
1361 }
1362
1363 impl$(< $($lifetimes),* >)? From<$struct_name$(< $($lifetimes),* >)?> for Vec<u8> {
1364 fn from(packet: $struct_name$(< $($lifetimes),* >)?) -> Vec<u8> {
1365 $crate::BanchoPacket::into_packet_data(packet)
1366 }
1367 }
1368 };
1369 (
1370 $packet_id: expr,
1371 $(#[$struct_meta:meta])*
1372 $struct_name:ident $(< $($lifetimes:lifetime),* >)? {
1373 $(
1374 $(#[$field_meta:meta])*
1375 $field_name:ident: $field_type:ty$(,)*
1376 )*
1377 }
1378 ) => {
1379 packet_struct!(
1380 $packet_id,
1381 $(#[$struct_meta])*
1382 $struct_name $(< $($lifetimes),* >)? {
1383 $(
1384 $(#[$field_meta])*
1385 $field_name: $field_type,
1386 )*
1387 },
1388 fn into_packet_data(self) -> Vec<u8> {
1389 $crate::packet!(
1390 Self::ID
1391 $(,self.$field_name)*
1392 )
1393 }
1394 );
1395 }
1396 }
1397}