From 5d5167347b53f16bcd5c840f2ad54375b346c7ee Mon Sep 17 00:00:00 2001 From: MeexReay Date: Fri, 2 May 2025 20:38:44 +0300 Subject: [PATCH] allow packet cancellation --- src/main.rs | 2 + src/server/event/mod.rs | 82 ++++++++++++++++++++++++----------------- src/server/protocol.rs | 38 +++++++++---------- 3 files changed, 68 insertions(+), 54 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6a083e5..4519672 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,6 +76,7 @@ impl PacketHandler for ExamplePacketHandler { &self, client: Arc, packet: &mut Packet, + cancelled: &mut bool, state: ConnectionState ) -> Result<(), ServerError> { debug!("{} -> S\t| 0x{:02x}\t| {:?}\t| {} bytes", client.addr.clone(), packet.id(), state, packet.len()); @@ -87,6 +88,7 @@ impl PacketHandler for ExamplePacketHandler { &self, client: Arc, packet: &mut Packet, + cancelled: &mut bool, state: ConnectionState ) -> Result<(), ServerError> { debug!("{} <- S\t| 0x{:02x}\t| {:?}\t| {} bytes", client.addr.clone(), packet.id(), state, packet.len()); diff --git a/src/server/event/mod.rs b/src/server/event/mod.rs index 0277fcf..fadb22c 100644 --- a/src/server/event/mod.rs +++ b/src/server/event/mod.rs @@ -17,52 +17,68 @@ macro_rules! generate_handlers { }; } -// Пример использования: -// let packet_dst = trigger_packet!(packet_src, client, Handshake, incoming); -// │ │ │ │ -// ┌────────────────────┼───────────┼────────┼──────────┘ -// │ │ │ │ -// │ ┌─────┼───────────┘ │ -// │ │ │ │ -// │ │ │ └──────────────────┐ -// │ ▼ └───────────┐ │ -// Сделается вот такой вызов на всех packet_handler'ах: ▼ ▼ ▼ -// handler.on_incoming_packet(client.clone(), &mut packet, ConnectionState::Handshake) -// packet_src можно заменить на получение пакета, например: trigger_packet!(client.conn().read_packet()?, client, Handshake, incoming); -// В packet_dst будет лежать обратботанный пакет, прошедший через все хандлеры -// TODO: сделать чтобы можно было ваще отключить обработку +/// Отправляет пакет клиенту и проходит по пакет ханлдерам +/// Пример использования: +/// +/// write_packet!(client, Handshake, packet); +/// +/// `Handshake` это режим подключения (типы ConnectionState) #[macro_export] -macro_rules! trigger_packet { - ($packet:expr, $client:ident, $state:ident, $bound:ident) => { +macro_rules! write_packet { + ($client:expr, $state:ident, $packet:expr) => { { - paste::paste! { - let mut packet = $packet; - for handler in $client.server.packet_handlers( - |o| o.[]() - ).iter() { - handler.[]($client.clone(), &mut packet, crate::server::protocol::ConnectionState::$state)?; - } + let mut packet = $packet; + let mut cancelled = false; + for handler in $client.server.packet_handlers( + |o| o.on_outcoming_packet_priority() + ).iter() { + handler.on_outcoming_packet($client.clone(), &mut packet, &mut cancelled, crate::server::protocol::ConnectionState::$state)?; packet.get_mut().set_position(0); - packet + } + if !cancelled { + $client.conn().write_packet(&packet)?; } } }; } -// Честно ни разу не проверял работу этого дерьма -// Пример использования: -// trigger_event!(client, status, $mut response, state); -// Сделается вот такой вызов на всех листенерах: -// listener.on_status(client.clone(), &mut response, state); +/// Читает пакет от клиента и проходит по пакет ханлдерам +/// Пример использования: +/// +/// let packet = read_packet!(client, Handshake); +/// +/// `Handshake` это режим подключения (типы ConnectionState) +#[macro_export] +macro_rules! read_packet { + ($client:expr, $state:ident) => { + loop { + let mut packet = $client.conn().read_packet()?; + let mut cancelled = false; + for handler in $client.server.packet_handlers( + |o| o.on_incoming_packet_priority() + ).iter() { + handler.on_incoming_packet($client.clone(), &mut packet, &mut cancelled, crate::server::protocol::ConnectionState::$state)?; + packet.get_mut().set_position(0); + } + if !cancelled { + break packet; + } + } + }; +} + +/// Пример использования: +/// +/// trigger_event!(client, status, &mut response, state); #[macro_export] macro_rules! trigger_event { - ($client:ident, $event:ident, $(, $arg_ty:ty)* $(,)?) => {{ + ($client:ident, $event:ident $(, $arg_ty:expr)* $(,)?) => {{ paste::paste! { for handler in $client.server.listeners( |o| o.[]() ).iter() { handler.[]( - $client.clone(), + $client.clone() $(, $arg_ty)* )?; } @@ -76,7 +92,7 @@ pub trait Listener: Sync + Send { } pub trait PacketHandler: Sync + Send { - generate_handlers!(incoming_packet, &mut Packet, ConnectionState); - generate_handlers!(outcoming_packet, &mut Packet, ConnectionState); + generate_handlers!(incoming_packet, &mut Packet, &mut bool, ConnectionState); + generate_handlers!(outcoming_packet, &mut Packet, &mut bool, ConnectionState); generate_handlers!(state, ConnectionState); } \ No newline at end of file diff --git a/src/server/protocol.rs b/src/server/protocol.rs index 1bfb11c..90c1e7d 100644 --- a/src/server/protocol.rs +++ b/src/server/protocol.rs @@ -4,7 +4,7 @@ use super::{player::context::{ClientContext, ClientInfo, Handshake, PlayerInfo}, use log::error; use rust_mc_proto::{DataReader, DataWriter, Packet}; -use crate::trigger_packet; +use crate::{trigger_event, write_packet, read_packet}; #[derive(Debug, Clone)] pub enum ConnectionState { @@ -22,7 +22,7 @@ pub fn handle_connection( // Получение пакетов производится через client.conn(), // ВАЖНО: не помещать сам client.conn() в переменные, // он должен сразу убиваться иначе соединение гдето задедлочится - let mut packet = trigger_packet!(client.conn().read_packet()?, client, Handshake, incoming); + let mut packet = read_packet!(client, Handshake); if packet.id() != 0x00 { return Err(ServerError::UnknownPacket(format!("Неизвестный пакет рукопожатия"))); @@ -46,7 +46,7 @@ pub fn handle_connection( loop { // Чтение запроса - let packet = trigger_packet!(client.conn().read_packet()?, client, Status, incoming); + let packet = read_packet!(client, Status); match packet.id() { 0x00 => { // Запрос статуса @@ -62,19 +62,15 @@ pub fn handle_connection( }".to_string(); // Опрос всех листенеров - for listener in client.server.listeners( // Цикл по листенерам - |o| o.on_status_priority() // Сортировка по приоритетности - ).iter() { - listener.on_status(client.clone(), &mut status)?; // Вызов метода листенера - } + trigger_event!(client, status, &mut status); // Отправка статуса packet.write_string(&status)?; - client.conn().write_packet(&trigger_packet!(packet, client, Status, outcoming))?; + write_packet!(client, Status, packet); }, 0x01 => { // Пинг - client.conn().write_packet(&trigger_packet!(packet, client, Status, outcoming))?; + write_packet!(client, Status, packet); // Просто отправляем этот же пакет обратно // ID такой-же, содержание тоже, так почему бы и нет? }, @@ -88,7 +84,7 @@ pub fn handle_connection( client.set_state(ConnectionState::Login)?; // Мы находимся в режиме Login // Читаем пакет Login Start - let mut packet = trigger_packet!(client.conn().read_packet()?, client, Login, incoming); + let mut packet = read_packet!(client, Login); let name = packet.read_string()?; let uuid = packet.read_uuid()?; @@ -104,18 +100,18 @@ pub fn handle_connection( // Отправляем пакет Set Compression если сжатие указано if let Some(threshold) = client.server.config.server.compression_threshold { - client.conn().write_packet(&trigger_packet!(Packet::build(0x03, |p| p.write_usize_varint(threshold))?, client, Login, outcoming))?; + write_packet!(client, Login, Packet::build(0x03, |p| p.write_usize_varint(threshold))?); client.conn().set_compression(Some(threshold)); // Устанавливаем сжатие на соединении } // Отправка пакета Login Success - client.conn().write_packet(&trigger_packet!(Packet::build(0x02, |p| { + write_packet!(client, Login, Packet::build(0x02, |p| { p.write_uuid(&uuid)?; p.write_string(&name)?; p.write_varint(0) - })?, client, Login, outcoming))?; + })?); - let packet = trigger_packet!(client.conn().read_packet()?, client, Login, incoming); + let packet = read_packet!(client, Login); if packet.id() != 0x03 { return Err(ServerError::UnknownPacket(format!("Неизвестный пакет при ожидании Login Acknowledged"))); @@ -126,7 +122,7 @@ pub fn handle_connection( // Получение бренда клиента из Serverbound Plugin Message // Identifier канала откуда берется бренд: minecraft:brand let brand = loop { - let mut packet = trigger_packet!(client.conn().read_packet()?, client, Configuration, incoming); + let mut packet = read_packet!(client, Configuration); if packet.id() == 0x02 { // Пакет Serverbound Plugin Message let identifier = packet.read_string()?; @@ -146,7 +142,7 @@ pub fn handle_connection( // debug!("brand: {brand}"); - let mut packet = trigger_packet!(client.conn().read_packet()?, client, Configuration, incoming); + let mut packet = read_packet!(client, Configuration); // Пакет Client Information if packet.id() != 0x00 { @@ -188,9 +184,9 @@ pub fn handle_connection( // TODO: Заюзать Listener'ы чтобы они подмешивали сюда чото - client.conn().write_packet(&trigger_packet!(Packet::empty(0x03), client, Configuration, outcoming))?; + write_packet!(client, Configuration, Packet::empty(0x03)); - let packet = trigger_packet!(client.conn().read_packet()?, client, Configuration, incoming); + let packet = read_packet!(client, Configuration); if packet.id() != 0x03 { return Err(ServerError::UnknownPacket(format!("Неизвестный пакет при ожидании Acknowledge Finish Configuration"))); @@ -200,12 +196,12 @@ pub fn handle_connection( // Отключение игрока с сообщением // Отправляет в формате NBT TAG_String (https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/NBT#Specification:string_tag) - client.conn().write_packet(&trigger_packet!(Packet::build(0x1C, |p| { + write_packet!(client, Play, Packet::build(0x1C, |p| { let message = "server is in developmenet lol".to_string(); p.write_byte(0x08)?; // NBT Type Name (TAG_String) p.write_unsigned_short(message.len() as u16)?; // String length in unsigned short p.write_bytes(message.as_bytes()) - })?, client, Play, outcoming))?; + })?); // TODO: Сделать отправку пакетов Play },