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.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
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]]
|
[[package]]
|
||||||
name = "rust_minecraft_server"
|
name = "rust_minecraft_server"
|
||||||
version = "0.1.0"
|
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"
|
||||||
|
@ -3,4 +3,7 @@ name = "rust_minecraft_server"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[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 {
|
pub enum ServerError {
|
||||||
ReadPacketError,
|
ReadPacketError,
|
||||||
ConnectionClosedError,
|
ConnectionClosedError,
|
||||||
@ -11,84 +10,10 @@ pub enum ServerError {
|
|||||||
PacketIsEnd
|
PacketIsEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for ServerError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
pub struct Packet {
|
f.write_str(&format!("{:?}", self))
|
||||||
size: i32,
|
}
|
||||||
data: Vec<u8>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Packet {
|
impl Error for ServerError {}
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
132
src/main.rs
132
src/main.rs
@ -1,40 +1,114 @@
|
|||||||
mod data;
|
use std::{error::Error, io::{Read, Write}, net::TcpListener, thread, time::Duration};
|
||||||
use data::{Packet, Server, Socket};
|
|
||||||
|
|
||||||
mod d;
|
use pohuy::Pohuy;
|
||||||
use d::*;
|
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 {
|
pub const HOST: &str = "127.0.0.1:25565";
|
||||||
if (i & -1 << (j * 7)) == 0 {
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
}; return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
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!("Сервер запущен на {}", HOST);
|
||||||
// println!("Не удалось забиндить сервер"); return;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// loop {
|
while let Ok((stream, addr)) = server.accept() {
|
||||||
// let socket = server.accept();
|
thread::spawn(move || {
|
||||||
// thread::spawn(move || { handle_connection(socket); });
|
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) {
|
fn handle_connection(
|
||||||
let Ok(packet) = Packet::read_from(&socket) else {return;};
|
mut conn: MinecraftConnection<impl Read + Write> // Подключение
|
||||||
// пакет уже имеет свой размер (size) и данные (data)
|
) -> Result<(), Box<dyn Error>> {
|
||||||
// надо поместить пакет в очередь, обработать по шаблону и отдать обработчику
|
// Чтение рукопожатия
|
||||||
|
let mut packet = conn.read_packet()?;
|
||||||
|
|
||||||
// fn on_keep_alive(socket: Socket, time: u64) {
|
if packet.id() != 0x00 { return Ok(()); } // Айди пакета не рукопожатное - выходим из функции
|
||||||
// if time != self.time {
|
|
||||||
// socket.close()
|
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