allow packet cancellation
This commit is contained in:
parent
8a1aa4b31f
commit
5d5167347b
@ -76,6 +76,7 @@ impl PacketHandler for ExamplePacketHandler {
|
|||||||
&self,
|
&self,
|
||||||
client: Arc<ClientContext>,
|
client: Arc<ClientContext>,
|
||||||
packet: &mut Packet,
|
packet: &mut Packet,
|
||||||
|
cancelled: &mut bool,
|
||||||
state: ConnectionState
|
state: ConnectionState
|
||||||
) -> Result<(), ServerError> {
|
) -> Result<(), ServerError> {
|
||||||
debug!("{} -> S\t| 0x{:02x}\t| {:?}\t| {} bytes", client.addr.clone(), packet.id(), state, packet.len());
|
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,
|
&self,
|
||||||
client: Arc<ClientContext>,
|
client: Arc<ClientContext>,
|
||||||
packet: &mut Packet,
|
packet: &mut Packet,
|
||||||
|
cancelled: &mut bool,
|
||||||
state: ConnectionState
|
state: ConnectionState
|
||||||
) -> Result<(), ServerError> {
|
) -> Result<(), ServerError> {
|
||||||
debug!("{} <- S\t| 0x{:02x}\t| {:?}\t| {} bytes", client.addr.clone(), packet.id(), state, packet.len());
|
debug!("{} <- S\t| 0x{:02x}\t| {:?}\t| {} bytes", client.addr.clone(), packet.id(), state, packet.len());
|
||||||
|
@ -17,52 +17,68 @@ macro_rules! generate_handlers {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Пример использования:
|
/// Отправляет пакет клиенту и проходит по пакет ханлдерам
|
||||||
// let packet_dst = trigger_packet!(packet_src, client, Handshake, incoming);
|
/// Пример использования:
|
||||||
// │ │ │ │
|
///
|
||||||
// ┌────────────────────┼───────────┼────────┼──────────┘
|
/// write_packet!(client, Handshake, packet);
|
||||||
// │ │ │ │
|
///
|
||||||
// │ ┌─────┼───────────┘ │
|
/// `Handshake` это режим подключения (типы ConnectionState)
|
||||||
// │ │ │ │
|
|
||||||
// │ │ │ └──────────────────┐
|
|
||||||
// │ ▼ └───────────┐ │
|
|
||||||
// Сделается вот такой вызов на всех 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: сделать чтобы можно было ваще отключить обработку
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! trigger_packet {
|
macro_rules! write_packet {
|
||||||
($packet:expr, $client:ident, $state:ident, $bound:ident) => {
|
($client:expr, $state:ident, $packet:expr) => {
|
||||||
{
|
{
|
||||||
paste::paste! {
|
let mut packet = $packet;
|
||||||
let mut packet = $packet;
|
let mut cancelled = false;
|
||||||
for handler in $client.server.packet_handlers(
|
for handler in $client.server.packet_handlers(
|
||||||
|o| o.[<on_ $bound _packet_priority>]()
|
|o| o.on_outcoming_packet_priority()
|
||||||
).iter() {
|
).iter() {
|
||||||
handler.[<on_ $bound _packet>]($client.clone(), &mut packet, crate::server::protocol::ConnectionState::$state)?;
|
handler.on_outcoming_packet($client.clone(), &mut packet, &mut cancelled, crate::server::protocol::ConnectionState::$state)?;
|
||||||
}
|
|
||||||
packet.get_mut().set_position(0);
|
packet.get_mut().set_position(0);
|
||||||
packet
|
}
|
||||||
|
if !cancelled {
|
||||||
|
$client.conn().write_packet(&packet)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Честно ни разу не проверял работу этого дерьма
|
/// Читает пакет от клиента и проходит по пакет ханлдерам
|
||||||
// Пример использования:
|
/// Пример использования:
|
||||||
// trigger_event!(client, status, $mut response, state);
|
///
|
||||||
// Сделается вот такой вызов на всех листенерах:
|
/// let packet = read_packet!(client, Handshake);
|
||||||
// listener.on_status(client.clone(), &mut response, state);
|
///
|
||||||
|
/// `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_export]
|
||||||
macro_rules! trigger_event {
|
macro_rules! trigger_event {
|
||||||
($client:ident, $event:ident, $(, $arg_ty:ty)* $(,)?) => {{
|
($client:ident, $event:ident $(, $arg_ty:expr)* $(,)?) => {{
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
for handler in $client.server.listeners(
|
for handler in $client.server.listeners(
|
||||||
|o| o.[<on_ $event _priority>]()
|
|o| o.[<on_ $event _priority>]()
|
||||||
).iter() {
|
).iter() {
|
||||||
handler.[<on_ $event>](
|
handler.[<on_ $event>](
|
||||||
$client.clone(),
|
$client.clone()
|
||||||
$(, $arg_ty)*
|
$(, $arg_ty)*
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -76,7 +92,7 @@ pub trait Listener: Sync + Send {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait PacketHandler: Sync + Send {
|
pub trait PacketHandler: Sync + Send {
|
||||||
generate_handlers!(incoming_packet, &mut Packet, ConnectionState);
|
generate_handlers!(incoming_packet, &mut Packet, &mut bool, ConnectionState);
|
||||||
generate_handlers!(outcoming_packet, &mut Packet, ConnectionState);
|
generate_handlers!(outcoming_packet, &mut Packet, &mut bool, ConnectionState);
|
||||||
generate_handlers!(state, ConnectionState);
|
generate_handlers!(state, ConnectionState);
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ use super::{player::context::{ClientContext, ClientInfo, Handshake, PlayerInfo},
|
|||||||
use log::error;
|
use log::error;
|
||||||
use rust_mc_proto::{DataReader, DataWriter, Packet};
|
use rust_mc_proto::{DataReader, DataWriter, Packet};
|
||||||
|
|
||||||
use crate::trigger_packet;
|
use crate::{trigger_event, write_packet, read_packet};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ConnectionState {
|
pub enum ConnectionState {
|
||||||
@ -22,7 +22,7 @@ pub fn handle_connection(
|
|||||||
// Получение пакетов производится через client.conn(),
|
// Получение пакетов производится через client.conn(),
|
||||||
// ВАЖНО: не помещать сам 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 {
|
if packet.id() != 0x00 {
|
||||||
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет рукопожатия")));
|
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет рукопожатия")));
|
||||||
@ -46,7 +46,7 @@ pub fn handle_connection(
|
|||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Чтение запроса
|
// Чтение запроса
|
||||||
let packet = trigger_packet!(client.conn().read_packet()?, client, Status, incoming);
|
let packet = read_packet!(client, Status);
|
||||||
|
|
||||||
match packet.id() {
|
match packet.id() {
|
||||||
0x00 => { // Запрос статуса
|
0x00 => { // Запрос статуса
|
||||||
@ -62,19 +62,15 @@ pub fn handle_connection(
|
|||||||
}".to_string();
|
}".to_string();
|
||||||
|
|
||||||
// Опрос всех листенеров
|
// Опрос всех листенеров
|
||||||
for listener in client.server.listeners( // Цикл по листенерам
|
trigger_event!(client, status, &mut status);
|
||||||
|o| o.on_status_priority() // Сортировка по приоритетности
|
|
||||||
).iter() {
|
|
||||||
listener.on_status(client.clone(), &mut status)?; // Вызов метода листенера
|
|
||||||
}
|
|
||||||
|
|
||||||
// Отправка статуса
|
// Отправка статуса
|
||||||
packet.write_string(&status)?;
|
packet.write_string(&status)?;
|
||||||
|
|
||||||
client.conn().write_packet(&trigger_packet!(packet, client, Status, outcoming))?;
|
write_packet!(client, Status, packet);
|
||||||
},
|
},
|
||||||
0x01 => { // Пинг
|
0x01 => { // Пинг
|
||||||
client.conn().write_packet(&trigger_packet!(packet, client, Status, outcoming))?;
|
write_packet!(client, Status, packet);
|
||||||
// Просто отправляем этот же пакет обратно
|
// Просто отправляем этот же пакет обратно
|
||||||
// ID такой-же, содержание тоже, так почему бы и нет?
|
// ID такой-же, содержание тоже, так почему бы и нет?
|
||||||
},
|
},
|
||||||
@ -88,7 +84,7 @@ pub fn handle_connection(
|
|||||||
client.set_state(ConnectionState::Login)?; // Мы находимся в режиме Login
|
client.set_state(ConnectionState::Login)?; // Мы находимся в режиме Login
|
||||||
|
|
||||||
// Читаем пакет Login Start
|
// Читаем пакет 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 name = packet.read_string()?;
|
||||||
let uuid = packet.read_uuid()?;
|
let uuid = packet.read_uuid()?;
|
||||||
@ -104,18 +100,18 @@ pub fn handle_connection(
|
|||||||
|
|
||||||
// Отправляем пакет Set Compression если сжатие указано
|
// Отправляем пакет Set Compression если сжатие указано
|
||||||
if let Some(threshold) = client.server.config.server.compression_threshold {
|
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)); // Устанавливаем сжатие на соединении
|
client.conn().set_compression(Some(threshold)); // Устанавливаем сжатие на соединении
|
||||||
}
|
}
|
||||||
|
|
||||||
// Отправка пакета Login Success
|
// Отправка пакета 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_uuid(&uuid)?;
|
||||||
p.write_string(&name)?;
|
p.write_string(&name)?;
|
||||||
p.write_varint(0)
|
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 {
|
if packet.id() != 0x03 {
|
||||||
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет при ожидании Login Acknowledged")));
|
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет при ожидании Login Acknowledged")));
|
||||||
@ -126,7 +122,7 @@ pub fn handle_connection(
|
|||||||
// Получение бренда клиента из Serverbound Plugin Message
|
// Получение бренда клиента из Serverbound Plugin Message
|
||||||
// Identifier канала откуда берется бренд: minecraft:brand
|
// Identifier канала откуда берется бренд: minecraft:brand
|
||||||
let brand = loop {
|
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
|
if packet.id() == 0x02 { // Пакет Serverbound Plugin Message
|
||||||
let identifier = packet.read_string()?;
|
let identifier = packet.read_string()?;
|
||||||
@ -146,7 +142,7 @@ pub fn handle_connection(
|
|||||||
|
|
||||||
// debug!("brand: {brand}");
|
// debug!("brand: {brand}");
|
||||||
|
|
||||||
let mut packet = trigger_packet!(client.conn().read_packet()?, client, Configuration, incoming);
|
let mut packet = read_packet!(client, Configuration);
|
||||||
|
|
||||||
// Пакет Client Information
|
// Пакет Client Information
|
||||||
if packet.id() != 0x00 {
|
if packet.id() != 0x00 {
|
||||||
@ -188,9 +184,9 @@ pub fn handle_connection(
|
|||||||
|
|
||||||
// TODO: Заюзать Listener'ы чтобы они подмешивали сюда чото
|
// 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 {
|
if packet.id() != 0x03 {
|
||||||
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет при ожидании Acknowledge Finish Configuration")));
|
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)
|
// Отправляет в формате 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();
|
let message = "server is in developmenet lol".to_string();
|
||||||
p.write_byte(0x08)?; // NBT Type Name (TAG_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_unsigned_short(message.len() as u16)?; // String length in unsigned short
|
||||||
p.write_bytes(message.as_bytes())
|
p.write_bytes(message.as_bytes())
|
||||||
})?, client, Play, outcoming))?;
|
})?);
|
||||||
|
|
||||||
// TODO: Сделать отправку пакетов Play
|
// TODO: Сделать отправку пакетов Play
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user