rewrite on rust mc proto
This commit is contained in:
parent
d55bc24c10
commit
86e519ed63
146
Cargo.lock
generated
146
Cargo.lock
generated
@ -2,6 +2,152 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_mc_proto"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "734168f5b9aef1991db4b11c0bcd71c0336b0a5ba98269f0df39b41b8463ac8c"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust_minecraft_server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rust_mc_proto",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
|
||||
|
@ -4,3 +4,6 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
rust_mc_proto = "0.1.19"
|
||||
serde = "1.0.219" # used in text component
|
||||
serde_json = "1.0.140"
|
||||
|
45
src/d.rs
45
src/d.rs
@ -1,45 +0,0 @@
|
||||
use std::ops::Index;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
pub enum BufferError {
|
||||
EndOfBuffer
|
||||
}
|
||||
|
||||
pub struct Buffer {
|
||||
bytes: Vec<u8>,
|
||||
index: usize
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn new(bytes: Vec<u8>, index: usize) -> Self {
|
||||
Buffer { bytes, index }
|
||||
}
|
||||
|
||||
pub fn read(&self, size: usize) -> Result<Vec<u8>, BufferError> {
|
||||
if self.index + size >= self.bytes.len() {return Err(BufferError::EndOfBuffer);}
|
||||
// self.index += size;
|
||||
Ok(self.bytes[self.index..self.index+size-1].to_vec())
|
||||
}
|
||||
|
||||
pub fn read2(&mut self, size: usize) -> Result<Vec<u8>, BufferError> {
|
||||
if self.index + size >= self.bytes.len() {return Err(BufferError::EndOfBuffer);}
|
||||
self.index += size;
|
||||
Ok(self.bytes[self.index..self.index+size-1].to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Sas {
|
||||
fn ts(&mut self);
|
||||
}
|
||||
|
||||
impl Sas for Buffer {
|
||||
fn ts(&mut self) {
|
||||
self.index += 1;
|
||||
}
|
||||
}
|
89
src/data.rs
89
src/data.rs
@ -1,7 +1,6 @@
|
||||
use std::{io::Read, net::{SocketAddr, TcpListener, TcpStream}};
|
||||
|
||||
|
||||
use std::{error::Error, fmt::Display};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ServerError {
|
||||
ReadPacketError,
|
||||
ConnectionClosedError,
|
||||
@ -11,84 +10,10 @@ pub enum ServerError {
|
||||
PacketIsEnd
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct Packet {
|
||||
size: i32,
|
||||
data: Vec<u8>
|
||||
impl Display for ServerError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&format!("{:?}", self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Packet {
|
||||
pub fn read_from(socket: &Socket) -> Result<Self, ServerError> {
|
||||
let (size, n) = socket.read_varint_size()?;
|
||||
let data = socket.read((size - n as i32) as usize)?;
|
||||
Ok(Packet { size, data })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct Socket {
|
||||
pub stream: TcpStream,
|
||||
pub addr: SocketAddr
|
||||
}
|
||||
|
||||
impl Socket {
|
||||
pub fn read(&self, size: usize) -> Result<Vec<u8>, ServerError>{
|
||||
let mut buf: Vec<u8> = vec![0; size];
|
||||
match (&self.stream).read(&mut buf) {
|
||||
Ok(n) => if n == size {
|
||||
Ok(buf)
|
||||
} else if n == 0 {
|
||||
Err(ServerError::ConnectionClosedError)
|
||||
} else {
|
||||
buf.truncate(n);
|
||||
buf.append(&mut self.read(size-n)?);
|
||||
Ok(buf)
|
||||
},
|
||||
Err(_) => Err(ServerError::ReadError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_varint_size(&self) -> Result<(i32, u8), ServerError>{
|
||||
let mut result = 0i32;
|
||||
let mut offset = 0;
|
||||
let mut byte: u8;
|
||||
loop {
|
||||
byte = self.read(1)?[0];
|
||||
result |= ((byte & 0x7F) << offset) as i32;
|
||||
if (byte & 0x80) == 0 {break;};
|
||||
offset += 7;
|
||||
if offset >= 32 {return Err(ServerError::VarIntIsTooBig)}
|
||||
}
|
||||
Ok((result, offset / 7))
|
||||
}
|
||||
|
||||
pub fn read_varint(&self) -> Result<i32, ServerError>{
|
||||
Ok(self.read_varint_size()?.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct Server {
|
||||
listener: TcpListener
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn new(addr: &str) -> Result<Self, ServerError> {
|
||||
match TcpListener::bind(addr) {
|
||||
Ok(listener) => Ok(Server { listener }),
|
||||
Err(_) => Err(ServerError::BindError)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn accept(&self) -> Socket {
|
||||
loop {
|
||||
match self.listener.accept() {
|
||||
Ok((stream, addr)) => return Socket {stream, addr},
|
||||
Err(_) => continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Error for ServerError {}
|
132
src/main.rs
132
src/main.rs
@ -1,40 +1,114 @@
|
||||
mod data;
|
||||
use data::{Packet, Server, Socket};
|
||||
use std::{error::Error, io::{Read, Write}, net::TcpListener, thread, time::Duration};
|
||||
|
||||
mod d;
|
||||
use d::*;
|
||||
use pohuy::Pohuy;
|
||||
use rust_mc_proto::{DataReader, DataWriter, MinecraftConnection, Packet};
|
||||
|
||||
use std::thread;
|
||||
pub mod pohuy;
|
||||
pub mod data;
|
||||
|
||||
fn get_byte_size(i: i32) -> u8 {
|
||||
for j in 1..4 {
|
||||
if (i & -1 << (j * 7)) == 0 {
|
||||
return j;
|
||||
}
|
||||
}; return 5;
|
||||
}
|
||||
// Сделать настройку хоста через конфиг
|
||||
pub const HOST: &str = "127.0.0.1:25565";
|
||||
|
||||
fn main() {
|
||||
println!("{}", get_byte_size(-2147483648));
|
||||
let Ok(server) = TcpListener::bind(HOST) else {
|
||||
println!("Не удалось забиндить сервер на {}", HOST);
|
||||
return;
|
||||
};
|
||||
|
||||
// let Ok(server) = Server::new("127.0.0.1:25565") else {
|
||||
// println!("Не удалось забиндить сервер"); return;
|
||||
// };
|
||||
println!("Сервер запущен на {}", HOST);
|
||||
|
||||
// loop {
|
||||
// let socket = server.accept();
|
||||
// thread::spawn(move || { handle_connection(socket); });
|
||||
// }
|
||||
while let Ok((stream, addr)) = server.accept() {
|
||||
thread::spawn(move || {
|
||||
println!("Подключение: {}", addr);
|
||||
|
||||
// Установка таймаутов на чтение и запись
|
||||
// По умолчанию пусть будет 5 секунд, надо будет сделать настройку через конфиг
|
||||
stream.set_read_timeout(Some(Duration::from_secs(5))).pohuy();
|
||||
stream.set_write_timeout(Some(Duration::from_secs(5))).pohuy();
|
||||
|
||||
// Обработка подключения
|
||||
// Если ошибка -> похуй
|
||||
handle_connection(MinecraftConnection::new(&stream)).pohuy();
|
||||
|
||||
println!("Отключение: {}", addr);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_connection(socket: Socket) {
|
||||
let Ok(packet) = Packet::read_from(&socket) else {return;};
|
||||
// пакет уже имеет свой размер (size) и данные (data)
|
||||
// надо поместить пакет в очередь, обработать по шаблону и отдать обработчику
|
||||
fn handle_connection(
|
||||
mut conn: MinecraftConnection<impl Read + Write> // Подключение
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
// Чтение рукопожатия
|
||||
let mut packet = conn.read_packet()?;
|
||||
|
||||
// fn on_keep_alive(socket: Socket, time: u64) {
|
||||
// if time != self.time {
|
||||
// socket.close()
|
||||
// }
|
||||
// }
|
||||
if packet.id() != 0x00 { return Ok(()); } // Айди пакета не рукопожатное - выходим из функции
|
||||
|
||||
let protocol_version = packet.read_varint()?; // Получаем версия протокола, может быть отрицательным если наш клиент дэбил
|
||||
let server_address = packet.read_string()?; // Получаем домен/адрес сервера к которому пытается подключиться клиент, например "play.example.com", а не айпи
|
||||
let server_port = packet.read_unsigned_short()?; // Все тоже самое что и с адресом сервера и все потому же и за тем же
|
||||
let next_state = packet.read_varint()?; // Тип подключения: 1 для получения статуса и пинга, 2 и 3 для обычного подключения
|
||||
|
||||
match next_state {
|
||||
1 => { // Тип подключения - статус
|
||||
loop {
|
||||
// Чтение запроса
|
||||
let packet = conn.read_packet()?;
|
||||
|
||||
match packet.id() {
|
||||
0x00 => { // Запрос статуса
|
||||
conn.write_packet(&Packet::build(0x00, |packet| {
|
||||
// Отправка статуса
|
||||
// В будущем это надо будет переделать чтобы это отправлялось через Listener'ы а не самим ядром сервера
|
||||
// Хотя можно сделать и дефолтное значение через конфиг
|
||||
packet.write_string(&format!(
|
||||
// Пример статуса с дебаг-инфой
|
||||
"{{
|
||||
\"version\": {{
|
||||
\"name\": \"1.21.5\",
|
||||
\"protocol\": {protocol_version}
|
||||
}},
|
||||
\"players\": {{
|
||||
\"max\": 100,
|
||||
\"online\": 5,
|
||||
\"sample\": [
|
||||
{{
|
||||
\"name\": \"thinkofdeath\",
|
||||
\"id\": \"4566e69f-c907-48ee-8d71-d7ba5aa00d20\"
|
||||
}}
|
||||
]
|
||||
}},
|
||||
\"description\": {{
|
||||
\"text\": \"pv: {protocol_version}, sp: {server_port}\nsa: {server_address}\"
|
||||
}},
|
||||
\"favicon\": \"data:image/png;base64,<data>\",
|
||||
\"enforcesSecureChat\": false
|
||||
}}"
|
||||
))
|
||||
})?)?;
|
||||
},
|
||||
0x01 => { // Пинг
|
||||
conn.write_packet(&packet)?;
|
||||
// Просто отправляем этот же пакет обратно
|
||||
// ID такой-же, содержание тоже, так почему бы и нет?
|
||||
},
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
2 | 3 => { // Тип подключения - игра
|
||||
// Отключение игрока с сообщением
|
||||
// Заглушка так сказать
|
||||
conn.write_packet(&Packet::build(0x00, |packet| {
|
||||
packet.write_string("{\"text\": \"This server is in developement!!\", \"color\": \"red\", \"bold\": true}")
|
||||
})?)?;
|
||||
|
||||
// TODO: Чтение Configuration (возможно с примешиванием Listener'ов)
|
||||
// TODO: Обработчик пакетов Play (тоже трейт), который уже будет дергать Listener'ы
|
||||
},
|
||||
_ => {} // Тип подключения не рукопожатный
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
5
src/pohuy.rs
Normal file
5
src/pohuy.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub trait Pohuy: Sized {
|
||||
fn pohuy(self) -> () {}
|
||||
}
|
||||
|
||||
impl<T, E> Pohuy for Result<T, E> {}
|
Loading…
Reference in New Issue
Block a user