added state field to client context
created protocol helper read+write nbt trait moved event behaviour to new module added event on state change to packet handler
This commit is contained in:
parent
ca7eb4e350
commit
1c3c3e0f63
67
Cargo.lock
generated
67
Cargo.lock
generated
@ -121,12 +121,6 @@ version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.20"
|
||||
@ -194,6 +188,17 @@ version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "craftflow-nbt"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a2d5312462b00f8420ace884a696f243be136ada9f50bf5f3d9858ff0c8e8e"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
@ -309,18 +314,6 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
|
||||
|
||||
[[package]]
|
||||
name = "fastnbt"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d4a73a95dc65551ccd98e1ecd1adb5d1ba5361146963b31f481ca42fc0520a3"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"cesu8",
|
||||
"serde",
|
||||
"serde_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.1"
|
||||
@ -569,6 +562,12 @@ dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.3"
|
||||
@ -718,11 +717,12 @@ name = "rust_minecraft_server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"colog",
|
||||
"craftflow-nbt",
|
||||
"dashmap",
|
||||
"fastnbt",
|
||||
"itertools",
|
||||
"log",
|
||||
"palette",
|
||||
"paste",
|
||||
"rust_mc_proto",
|
||||
"serde",
|
||||
"serde_default",
|
||||
@ -759,15 +759,6 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_bytes"
|
||||
version = "0.11.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_default"
|
||||
version = "0.2.0"
|
||||
@ -877,6 +868,26 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
|
@ -12,8 +12,9 @@ serde_default = "0.2.0"
|
||||
toml = "0.8.22"
|
||||
itertools = "0.14.0"
|
||||
palette = "0.7.6"
|
||||
fastnbt = "2.5.0"
|
||||
craftflow-nbt = "2.1.0"
|
||||
colog = "1.3.0"
|
||||
log = "0.4.27"
|
||||
uuid = "1.16.0"
|
||||
dashmap = "6.1.0"
|
||||
paste = "1.0.15"
|
||||
|
@ -2,10 +2,10 @@ use std::{hash::Hash, net::{SocketAddr, TcpStream}, sync::{Arc, RwLock, RwLockWr
|
||||
|
||||
use dashmap::DashMap;
|
||||
use itertools::Itertools;
|
||||
use rust_mc_proto::{MinecraftConnection, Packet};
|
||||
use rust_mc_proto::MinecraftConnection;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{config::Config, data::ServerError, player::{ClientInfo, Handshake, PlayerInfo}};
|
||||
use crate::{config::Config, data::ServerError, event::{ConnectionState, Listener, PacketHandler}, player::{ClientInfo, Handshake, PlayerInfo, ProtocolHelper}};
|
||||
|
||||
pub struct ServerContext {
|
||||
pub config: Arc<Config>,
|
||||
@ -90,11 +90,12 @@ impl ServerContext {
|
||||
|
||||
pub struct ClientContext {
|
||||
pub server: Arc<ServerContext>,
|
||||
pub conn: RwLock<MinecraftConnection<TcpStream>>,
|
||||
pub addr: SocketAddr,
|
||||
pub handshake: RwLock<Option<Handshake>>,
|
||||
pub client_info: RwLock<Option<ClientInfo>>,
|
||||
pub player_info: RwLock<Option<PlayerInfo>>
|
||||
conn: RwLock<MinecraftConnection<TcpStream>>,
|
||||
handshake: RwLock<Option<Handshake>>,
|
||||
client_info: RwLock<Option<ClientInfo>>,
|
||||
player_info: RwLock<Option<PlayerInfo>>,
|
||||
state: RwLock<ConnectionState>
|
||||
}
|
||||
|
||||
impl PartialEq for ClientContext {
|
||||
@ -111,7 +112,6 @@ impl Hash for ClientContext {
|
||||
|
||||
impl Eq for ClientContext {}
|
||||
|
||||
|
||||
impl ClientContext {
|
||||
pub fn new(
|
||||
server: Arc<ServerContext>,
|
||||
@ -123,7 +123,8 @@ impl ClientContext {
|
||||
conn: RwLock::new(conn),
|
||||
handshake: RwLock::new(None),
|
||||
client_info: RwLock::new(None),
|
||||
player_info: RwLock::new(None)
|
||||
player_info: RwLock::new(None),
|
||||
state: RwLock::new(ConnectionState::Handshake)
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,6 +140,18 @@ impl ClientContext {
|
||||
*self.player_info.write().unwrap() = Some(player_info);
|
||||
}
|
||||
|
||||
pub fn set_state(self: &Arc<Self>, state: ConnectionState) -> Result<(), ServerError> {
|
||||
*self.state.write().unwrap() = state.clone();
|
||||
|
||||
for handler in self.server.packet_handlers(
|
||||
|o| o.on_state_priority()
|
||||
).iter() {
|
||||
handler.on_state(self.clone(), state.clone())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handshake(self: &Arc<Self>) -> Option<Handshake> {
|
||||
self.handshake.read().unwrap().clone()
|
||||
}
|
||||
@ -151,60 +164,15 @@ impl ClientContext {
|
||||
self.player_info.read().unwrap().clone()
|
||||
}
|
||||
|
||||
pub fn state(self: &Arc<Self>) -> ConnectionState {
|
||||
self.state.read().unwrap().clone()
|
||||
}
|
||||
|
||||
pub fn conn(self: &Arc<Self>) -> RwLockWriteGuard<'_, MinecraftConnection<TcpStream>> {
|
||||
self.conn.write().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Listener: Sync + Send {
|
||||
fn on_status_priority(&self) -> i8 { 0 }
|
||||
fn on_status(&self, _: Arc<ClientContext>, _: &mut String) -> Result<(), ServerError> { Ok(()) }
|
||||
}
|
||||
|
||||
pub trait PacketHandler: Sync + Send {
|
||||
fn on_incoming_packet_priority(&self) -> i8 { 0 }
|
||||
fn on_incoming_packet(&self, _: Arc<ClientContext>, _: &mut Packet, _: ConnectionState) -> Result<(), ServerError> { Ok(()) }
|
||||
|
||||
fn on_outcoming_packet_priority(&self) -> i8 { 0 }
|
||||
fn on_outcoming_packet(&self, _: Arc<ClientContext>, _: &mut Packet, _: ConnectionState) -> Result<(), ServerError> { Ok(()) }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConnectionState {
|
||||
Handshake,
|
||||
Status,
|
||||
Login,
|
||||
Configuration,
|
||||
Play
|
||||
}
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! call_handlers {
|
||||
($packet:expr, $client:ident, $state:ident, incoming) => {
|
||||
{
|
||||
use crate::context::ConnectionState;
|
||||
let mut packet = $packet;
|
||||
for handler in $client.server.packet_handlers(
|
||||
|o| o.on_incoming_packet_priority()
|
||||
).iter() {
|
||||
handler.on_incoming_packet($client.clone(), &mut packet, ConnectionState::$state)?;
|
||||
pub fn protocol_helper(self: &Arc<Self>) -> ProtocolHelper {
|
||||
ProtocolHelper::new(self.clone())
|
||||
}
|
||||
packet.get_mut().set_position(0);
|
||||
packet
|
||||
}
|
||||
};
|
||||
($packet:expr, $client:ident, $state:ident, outcoming) => {
|
||||
{
|
||||
use crate::context::ConnectionState;
|
||||
let mut packet = $packet;
|
||||
for handler in $client.server.packet_handlers(
|
||||
|o| o.on_outcoming_packet_priority()
|
||||
).iter() {
|
||||
handler.on_outcoming_packet($client.clone(), &mut packet, ConnectionState::$state)?;
|
||||
}
|
||||
packet.get_mut().set_position(0);
|
||||
packet
|
||||
}
|
||||
};
|
||||
}
|
45
src/data.rs
45
src/data.rs
@ -1,8 +1,8 @@
|
||||
use std::{error::Error, fmt::Display};
|
||||
use std::{error::Error, fmt::Display, io::Read};
|
||||
use palette::{Hsl, IntoColor, Srgb};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use rust_mc_proto::ProtocolError;
|
||||
use rust_mc_proto::{DataReader, Packet, ProtocolError};
|
||||
use serde_with::skip_serializing_none;
|
||||
|
||||
// Ошибки сервера
|
||||
@ -12,7 +12,8 @@ pub enum ServerError {
|
||||
Protocol(ProtocolError),
|
||||
ConnectionClosed,
|
||||
SerTextComponent,
|
||||
DeTextComponent
|
||||
DeTextComponent,
|
||||
UnexpectedState
|
||||
}
|
||||
|
||||
impl Display for ServerError {
|
||||
@ -94,16 +95,6 @@ impl TextComponent {
|
||||
TextComponentBuilder::new()
|
||||
}
|
||||
|
||||
pub fn as_nbt(self) -> Result<Vec<u8>, ServerError> {
|
||||
fastnbt::to_bytes(&self)
|
||||
.map_err(|_| ServerError::SerTextComponent)
|
||||
}
|
||||
|
||||
pub fn from_nbt(bytes: &[u8]) -> Result<TextComponent, ServerError> {
|
||||
fastnbt::from_bytes(bytes)
|
||||
.map_err(|_| ServerError::DeTextComponent)
|
||||
}
|
||||
|
||||
pub fn as_json(self) -> Result<String, ServerError> {
|
||||
serde_json::to_string(&self)
|
||||
.map_err(|_| ServerError::SerTextComponent)
|
||||
@ -115,6 +106,34 @@ impl TextComponent {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TextComponent {
|
||||
fn default() -> Self {
|
||||
Self::new(String::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ReadWriteNBT<T>: DataReader {
|
||||
fn read_nbt(&mut self) -> Result<T, ServerError>;
|
||||
fn write_nbt(&mut self, val: &T) -> Result<(), ServerError>;
|
||||
}
|
||||
|
||||
impl ReadWriteNBT<TextComponent> for Packet {
|
||||
fn read_nbt(&mut self) -> Result<TextComponent, ServerError> {
|
||||
let mut data = Vec::new();
|
||||
let pos = self.get_ref().position();
|
||||
self.get_mut().read_to_end(&mut data).map_err(|_| ServerError::DeTextComponent)?;
|
||||
let (remaining, value) = craftflow_nbt::from_slice(&data).map_err(|_| ServerError::DeTextComponent)?;
|
||||
self.get_mut().set_position(pos + (data.len() - remaining.len()) as u64);
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn write_nbt(&mut self, val: &TextComponent) -> Result<(), ServerError> {
|
||||
craftflow_nbt::to_writer(self.get_mut(), val)
|
||||
.map_err(|_| ServerError::SerTextComponent)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextComponentBuilder {
|
||||
text: String,
|
||||
color: Option<String>,
|
||||
|
101
src/event.rs
Normal file
101
src/event.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use rust_mc_proto::Packet;
|
||||
|
||||
use crate::{context::ClientContext, data::ServerError};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! generate_handlers {
|
||||
($name:ident $(, $arg_ty:ty)* $(,)?) => {
|
||||
paste::paste! {
|
||||
fn [<on_ $name _priority>](&self) -> i8 {
|
||||
0
|
||||
}
|
||||
|
||||
fn [<on_ $name>](&self, _: std::sync::Arc<ClientContext> $(, _: $arg_ty)*) -> Result<(), ServerError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! trigger_packet {
|
||||
($packet:expr, $client:ident, $state:ident, $bound:ident) => {
|
||||
{
|
||||
paste::paste! {
|
||||
let mut packet = $packet;
|
||||
for handler in $client.server.packet_handlers(
|
||||
|o| o.[<on_ $bound _packet_priority>]()
|
||||
).iter() {
|
||||
handler.[<on_ $bound _packet>]($client.clone(), &mut packet, crate::event::ConnectionState::$state)?;
|
||||
}
|
||||
packet.get_mut().set_position(0);
|
||||
packet
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! trigger_event {
|
||||
($client:ident, $event:ident, $($arg:expr),* $(,)?) => {{
|
||||
paste::paste! {
|
||||
trigger_event!(@declare_mut_vars 0, $($arg),*);
|
||||
|
||||
for handler in $client.server.listeners(
|
||||
|o| o.[<on_ $event _priority>]()
|
||||
).iter() {
|
||||
handler.[<on_ $event>](
|
||||
$client.clone(),
|
||||
$(trigger_event!(@expand_arg 0, $arg)),*
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}};
|
||||
|
||||
(@declare_mut_vars $i:tt, &mut $head:expr, $($tail:tt)*) => {
|
||||
paste::paste! {
|
||||
let mut [<__arg $i>] = $head;
|
||||
}
|
||||
trigger_event!(@declare_mut_vars trigger_event!(@inc $i), $($tail)*);
|
||||
};
|
||||
(@declare_mut_vars $i:tt, $head:expr, $($tail:tt)*) => {
|
||||
trigger_event!(@declare_mut_vars trigger_event!(@inc $i), $($tail)*);
|
||||
};
|
||||
(@declare_mut_vars $_i:tt,) => {};
|
||||
|
||||
(@expand_arg $i:tt, &mut $head:expr) => {
|
||||
paste::paste! { &mut [<__arg $i>] }
|
||||
};
|
||||
(@expand_arg $_i:tt, $head:expr) => {
|
||||
$head
|
||||
};
|
||||
|
||||
(@inc 0) => { 1 };
|
||||
(@inc 1) => { 2 };
|
||||
(@inc 2) => { 3 };
|
||||
(@inc 3) => { 4 };
|
||||
(@inc 4) => { 5 };
|
||||
(@inc 5) => { 6 };
|
||||
(@inc 6) => { 7 };
|
||||
(@inc 7) => { 8 };
|
||||
}
|
||||
|
||||
pub trait Listener: Sync + Send {
|
||||
generate_handlers!(status, &mut String);
|
||||
generate_handlers!(plugin_message, &mut String);
|
||||
}
|
||||
|
||||
pub trait PacketHandler: Sync + Send {
|
||||
generate_handlers!(incoming_packet, &mut Packet, ConnectionState);
|
||||
generate_handlers!(outcoming_packet, &mut Packet, ConnectionState);
|
||||
generate_handlers!(state, ConnectionState);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ConnectionState {
|
||||
Handshake,
|
||||
Status,
|
||||
Login,
|
||||
Configuration,
|
||||
Play
|
||||
}
|
38
src/main.rs
38
src/main.rs
@ -1,7 +1,8 @@
|
||||
use std::{env::args, io::Read, net::TcpListener, path::PathBuf, sync::Arc, thread, time::Duration};
|
||||
|
||||
use config::Config;
|
||||
use context::{ClientContext, ConnectionState, Listener, PacketHandler, ServerContext};
|
||||
use event::{ConnectionState, Listener, PacketHandler};
|
||||
use context::{ClientContext, ServerContext};
|
||||
use log::{debug, error, info};
|
||||
use player::{ClientInfo, Handshake, PlayerInfo};
|
||||
use rust_mc_proto::{DataReader, DataWriter, MinecraftConnection, Packet};
|
||||
@ -11,6 +12,7 @@ use pohuy::Pohuy;
|
||||
|
||||
pub mod config;
|
||||
pub mod data;
|
||||
pub mod event;
|
||||
pub mod context;
|
||||
pub mod player;
|
||||
pub mod pohuy;
|
||||
@ -194,7 +196,7 @@ fn handle_connection(
|
||||
// Получение пакетов производится через client.conn(),
|
||||
// ВАЖНО: не помещать сам client.conn() в переменные,
|
||||
// он должен сразу убиваться иначе соединение гдето задедлочится
|
||||
let mut packet = call_handlers!(client.conn().read_packet()?, client, Handshake, incoming);
|
||||
let mut packet = trigger_packet!(client.conn().read_packet()?, client, Handshake, incoming);
|
||||
|
||||
if packet.id() != 0x00 {
|
||||
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет рукопожатия")));
|
||||
@ -214,9 +216,11 @@ fn handle_connection(
|
||||
|
||||
match next_state {
|
||||
1 => { // Тип подключения - статус
|
||||
client.set_state(ConnectionState::Status)?; // Мы находимся в режиме Status
|
||||
|
||||
loop {
|
||||
// Чтение запроса
|
||||
let packet = call_handlers!(client.conn().read_packet()?, client, Status, incoming);
|
||||
let packet = trigger_packet!(client.conn().read_packet()?, client, Status, incoming);
|
||||
|
||||
match packet.id() {
|
||||
0x00 => { // Запрос статуса
|
||||
@ -241,10 +245,10 @@ fn handle_connection(
|
||||
// Отправка статуса
|
||||
packet.write_string(&status)?;
|
||||
|
||||
client.conn().write_packet(&call_handlers!(packet, client, Status, outcoming))?;
|
||||
client.conn().write_packet(&trigger_packet!(packet, client, Status, outcoming))?;
|
||||
},
|
||||
0x01 => { // Пинг
|
||||
client.conn().write_packet(&call_handlers!(packet, client, Status, outcoming))?;
|
||||
client.conn().write_packet(&trigger_packet!(packet, client, Status, outcoming))?;
|
||||
// Просто отправляем этот же пакет обратно
|
||||
// ID такой-же, содержание тоже, так почему бы и нет?
|
||||
},
|
||||
@ -255,10 +259,10 @@ fn handle_connection(
|
||||
}
|
||||
},
|
||||
2 => { // Тип подключения - игра
|
||||
// Мы находимся в режиме Login
|
||||
client.set_state(ConnectionState::Login)?; // Мы находимся в режиме Login
|
||||
|
||||
// Читаем пакет Login Start
|
||||
let mut packet = call_handlers!(client.conn().read_packet()?, client, Login, incoming);
|
||||
let mut packet = trigger_packet!(client.conn().read_packet()?, client, Login, incoming);
|
||||
|
||||
let name = packet.read_string()?;
|
||||
let uuid = packet.read_uuid()?;
|
||||
@ -274,29 +278,29 @@ fn handle_connection(
|
||||
|
||||
// Отправляем пакет Set Compression если сжатие указано
|
||||
if let Some(threshold) = client.server.config.server.compression_threshold {
|
||||
client.conn().write_packet(&call_handlers!(Packet::build(0x03, |p| p.write_usize_varint(threshold))?, client, Login, outcoming))?;
|
||||
client.conn().write_packet(&trigger_packet!(Packet::build(0x03, |p| p.write_usize_varint(threshold))?, client, Login, outcoming))?;
|
||||
client.conn().set_compression(Some(threshold)); // Устанавливаем сжатие на соединении
|
||||
}
|
||||
|
||||
// Отправка пакета Login Success
|
||||
client.conn().write_packet(&call_handlers!(Packet::build(0x02, |p| {
|
||||
client.conn().write_packet(&trigger_packet!(Packet::build(0x02, |p| {
|
||||
p.write_uuid(&uuid)?;
|
||||
p.write_string(&name)?;
|
||||
p.write_varint(0)
|
||||
})?, client, Login, outcoming))?;
|
||||
|
||||
let packet = call_handlers!(client.conn().read_packet()?, client, Login, incoming);
|
||||
let packet = trigger_packet!(client.conn().read_packet()?, client, Login, incoming);
|
||||
|
||||
if packet.id() != 0x03 {
|
||||
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет при ожидании Login Acknowledged")));
|
||||
}
|
||||
|
||||
// Мы перешли в режим Configuration
|
||||
client.set_state(ConnectionState::Configuration)?; // Мы перешли в режим Configuration
|
||||
|
||||
// Получение бренда клиента из Serverbound Plugin Message
|
||||
// Identifier канала откуда берется бренд: minecraft:brand
|
||||
let brand = loop {
|
||||
let mut packet = call_handlers!(client.conn().read_packet()?, client, Configuration, incoming);
|
||||
let mut packet = trigger_packet!(client.conn().read_packet()?, client, Configuration, incoming);
|
||||
|
||||
if packet.id() == 0x02 { // Пакет Serverbound Plugin Message
|
||||
let identifier = packet.read_string()?;
|
||||
@ -316,7 +320,7 @@ fn handle_connection(
|
||||
|
||||
// debug!("brand: {brand}");
|
||||
|
||||
let mut packet = call_handlers!(client.conn().read_packet()?, client, Configuration, incoming);
|
||||
let mut packet = trigger_packet!(client.conn().read_packet()?, client, Configuration, incoming);
|
||||
|
||||
// Пакет Client Information
|
||||
if packet.id() != 0x00 {
|
||||
@ -358,19 +362,19 @@ fn handle_connection(
|
||||
|
||||
// TODO: Заюзать Listener'ы чтобы они подмешивали сюда чото
|
||||
|
||||
client.conn().write_packet(&call_handlers!(Packet::empty(0x03), client, Configuration, outcoming))?;
|
||||
client.conn().write_packet(&trigger_packet!(Packet::empty(0x03), client, Configuration, outcoming))?;
|
||||
|
||||
let packet = call_handlers!(client.conn().read_packet()?, client, Configuration, incoming);
|
||||
let packet = trigger_packet!(client.conn().read_packet()?, client, Configuration, incoming);
|
||||
|
||||
if packet.id() != 0x03 {
|
||||
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет при ожидании Acknowledge Finish Configuration")));
|
||||
}
|
||||
|
||||
// Мы перешли в режим Play
|
||||
client.set_state(ConnectionState::Play)?; // Мы перешли в режим Play
|
||||
|
||||
// Отключение игрока с сообщением
|
||||
// Отправляет в формате NBT TAG_String (https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/NBT#Specification:string_tag)
|
||||
client.conn().write_packet(&call_handlers!(Packet::build(0x1C, |p| {
|
||||
client.conn().write_packet(&trigger_packet!(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
|
||||
|
105
src/player.rs
105
src/player.rs
@ -1,5 +1,10 @@
|
||||
use std::{io::Read, sync::Arc};
|
||||
|
||||
use rust_mc_proto::{DataReader, DataWriter, Packet};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{context::ClientContext, data::{ServerError, TextComponent, ReadWriteNBT}, event::ConnectionState};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Handshake {
|
||||
pub protocol_version: i32,
|
||||
@ -26,3 +31,103 @@ pub struct PlayerInfo {
|
||||
pub name: String,
|
||||
pub uuid: Uuid
|
||||
}
|
||||
|
||||
pub struct ProtocolHelper {
|
||||
client: Arc<ClientContext>,
|
||||
state: ConnectionState
|
||||
}
|
||||
|
||||
impl ProtocolHelper {
|
||||
pub fn new(client: Arc<ClientContext>) -> Self {
|
||||
Self {
|
||||
state: client.state(),
|
||||
client
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disconnect(&self, reason: TextComponent) -> Result<(), ServerError> {
|
||||
let packet = match self.state {
|
||||
ConnectionState::Login => {
|
||||
let text = reason.as_json()?;
|
||||
Packet::build(0x00, |p| p.write_string(&text))?
|
||||
},
|
||||
ConnectionState::Configuration => {
|
||||
let mut packet = Packet::empty(0x02);
|
||||
packet.write_nbt(&reason)?;
|
||||
packet
|
||||
},
|
||||
ConnectionState::Play => {
|
||||
let mut packet = Packet::empty(0x1C);
|
||||
packet.write_nbt(&reason)?;
|
||||
packet
|
||||
},
|
||||
_ => {
|
||||
self.client.conn().close();
|
||||
return Ok(())
|
||||
},
|
||||
};
|
||||
self.client.conn().write_packet(&packet)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns cookie content
|
||||
pub fn request_cookie(&self, id: &str) -> Result<Option<Vec<u8>>, ServerError> {
|
||||
match self.state {
|
||||
ConnectionState::Configuration => {
|
||||
let mut packet = Packet::empty(0x00);
|
||||
packet.write_string(id)?;
|
||||
self.client.conn().write_packet(&packet)?;
|
||||
|
||||
let mut packet = self.client.conn().read_packet()?;
|
||||
packet.read_string()?;
|
||||
let data = if packet.read_boolean()? {
|
||||
let n = packet.read_usize_varint()?;
|
||||
Some(packet.read_bytes(n)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(data)
|
||||
},
|
||||
_ => Err(ServerError::UnexpectedState)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns login plugin response - (message_id, payload)
|
||||
pub fn send_login_plugin_request(&self, id: i32, channel: &str, data: &[u8]) -> Result<(i32, Option<Vec<u8>>), ServerError> {
|
||||
match self.state {
|
||||
ConnectionState::Login => {
|
||||
let mut packet = Packet::empty(0x04);
|
||||
packet.write_varint(id)?;
|
||||
packet.write_string(channel)?;
|
||||
packet.write_bytes(data)?;
|
||||
self.client.conn().write_packet(&packet)?;
|
||||
|
||||
let mut packet = self.client.conn().read_packet()?;
|
||||
let identifier = packet.read_varint()?;
|
||||
let data = if packet.read_boolean()? {
|
||||
let mut data = Vec::new();
|
||||
packet.get_mut().read_to_end(&mut data).unwrap();
|
||||
Some(data)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok((identifier, data))
|
||||
},
|
||||
_ => Err(ServerError::UnexpectedState)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_plugin_message(&self, channel: &str, data: &[u8]) -> Result<(), ServerError> {
|
||||
let mut packet = match self.state {
|
||||
ConnectionState::Configuration => Packet::empty(0x01),
|
||||
ConnectionState::Play => Packet::empty(0x18),
|
||||
_ => return Err(ServerError::UnexpectedState)
|
||||
};
|
||||
packet.write_string(channel)?;
|
||||
packet.write_bytes(data)?;
|
||||
self.client.conn().write_packet(&packet)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user