configuration and login states
This commit is contained in:
parent
f8684a0402
commit
59efaa2861
143
Cargo.lock
generated
143
Cargo.lock
generated
@ -23,6 +23,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "approx"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@ -41,6 +50,18 @@ version = "3.17.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "by_address"
|
||||||
|
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]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.20"
|
version = "1.2.20"
|
||||||
@ -50,6 +71,12 @@ dependencies = [
|
|||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cesu8"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -141,6 +168,24 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fast-srgb8"
|
||||||
|
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]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@ -300,6 +345,72 @@ version = "1.21.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "palette"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6"
|
||||||
|
dependencies = [
|
||||||
|
"approx",
|
||||||
|
"fast-srgb8",
|
||||||
|
"palette_derive",
|
||||||
|
"phf",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "palette_derive"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30"
|
||||||
|
dependencies = [
|
||||||
|
"by_address",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
|
||||||
|
dependencies = [
|
||||||
|
"phf_macros",
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator",
|
||||||
|
"phf_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powerfmt"
|
name = "powerfmt"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -324,6 +435,21 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust_mc_proto"
|
name = "rust_mc_proto"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
@ -338,7 +464,9 @@ dependencies = [
|
|||||||
name = "rust_minecraft_server"
|
name = "rust_minecraft_server"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"fastnbt",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"palette",
|
||||||
"rust_mc_proto",
|
"rust_mc_proto",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_default",
|
"serde_default",
|
||||||
@ -368,6 +496,15 @@ dependencies = [
|
|||||||
"serde_derive",
|
"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]]
|
[[package]]
|
||||||
name = "serde_default"
|
name = "serde_default"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -448,6 +585,12 @@ version = "1.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
|
@ -11,3 +11,5 @@ serde_with = { version = "3.12.0", features = ["macros"] }
|
|||||||
serde_default = "0.2.0"
|
serde_default = "0.2.0"
|
||||||
toml = "0.8.22"
|
toml = "0.8.22"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
|
palette = "0.7.6"
|
||||||
|
fastnbt = "2.5.0"
|
||||||
|
@ -5,27 +5,37 @@ use serde_default::DefaultFromSerde;
|
|||||||
|
|
||||||
|
|
||||||
#[derive(Debug, DefaultFromSerde, Serialize, Deserialize, Clone)]
|
#[derive(Debug, DefaultFromSerde, Serialize, Deserialize, Clone)]
|
||||||
pub struct ServerConfig {
|
pub struct BindConfig {
|
||||||
/// Хост где забиндить сервер
|
|
||||||
#[serde(default = "default_host")] pub host: String,
|
#[serde(default = "default_host")] pub host: String,
|
||||||
|
|
||||||
/// Таймаут подключения в секундах
|
|
||||||
#[serde(default = "default_timeout")] pub timeout: u64,
|
#[serde(default = "default_timeout")] pub timeout: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, DefaultFromSerde, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct ServerConfig {
|
||||||
|
#[serde(default)] pub online_mode: bool,
|
||||||
|
#[serde(default = "default_compression")] pub compression_threshold: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, DefaultFromSerde, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct Config {
|
||||||
|
#[serde(default)] pub bind: BindConfig,
|
||||||
|
#[serde(default)] pub server: ServerConfig,
|
||||||
|
}
|
||||||
|
|
||||||
fn default_host() -> String { "127.0.0.1:25565".to_string() }
|
fn default_host() -> String { "127.0.0.1:25565".to_string() }
|
||||||
fn default_timeout() -> u64 { 5 }
|
fn default_timeout() -> u64 { 5 }
|
||||||
|
fn default_compression() -> Option<usize> { Some(256) }
|
||||||
|
|
||||||
impl ServerConfig {
|
impl Config {
|
||||||
pub fn load_from_file(path: PathBuf) -> Option<ServerConfig> {
|
pub fn load_from_file(path: PathBuf) -> Option<Config> {
|
||||||
if !fs::exists(&path).unwrap_or_default() {
|
if !fs::exists(&path).unwrap_or_default() {
|
||||||
let table = ServerConfig::default();
|
let table = Config::default();
|
||||||
fs::create_dir_all(&path.parent()?).ok()?;
|
fs::create_dir_all(&path.parent()?).ok()?;
|
||||||
fs::write(&path, toml::to_string_pretty(&table).ok()?).ok()?;
|
fs::write(&path, toml::to_string_pretty(&table).ok()?).ok()?;
|
||||||
return Some(table);
|
return Some(table);
|
||||||
}
|
}
|
||||||
let content = fs::read_to_string(&path).ok()?;
|
let content = fs::read_to_string(&path).ok()?;
|
||||||
let table = toml::from_str::<ServerConfig>(&content).ok()?;
|
let table = toml::from_str::<Config>(&content).ok()?;
|
||||||
Some(table)
|
Some(table)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,16 +3,16 @@ use std::{net::{SocketAddr, TcpStream}, sync::{atomic::{AtomicI32, AtomicU16, Or
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rust_mc_proto::{MinecraftConnection, Packet};
|
use rust_mc_proto::{MinecraftConnection, Packet};
|
||||||
|
|
||||||
use crate::{config::ServerConfig, data::ServerError};
|
use crate::{config::Config, data::ServerError};
|
||||||
|
|
||||||
pub struct ServerContext {
|
pub struct ServerContext {
|
||||||
pub config: Arc<ServerConfig>,
|
pub config: Arc<Config>,
|
||||||
listeners: Vec<Box<dyn Listener>>,
|
listeners: Vec<Box<dyn Listener>>,
|
||||||
handlers: Vec<Box<dyn PacketHandler>>
|
handlers: Vec<Box<dyn PacketHandler>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerContext {
|
impl ServerContext {
|
||||||
pub fn new(config: Arc<ServerConfig>) -> ServerContext {
|
pub fn new(config: Arc<Config>) -> ServerContext {
|
||||||
ServerContext {
|
ServerContext {
|
||||||
config,
|
config,
|
||||||
listeners: Vec::new(),
|
listeners: Vec::new(),
|
||||||
|
93
src/data.rs
93
src/data.rs
@ -1,7 +1,8 @@
|
|||||||
use std::{error::Error, fmt::Display};
|
use std::{error::Error, fmt::Display};
|
||||||
|
use palette::{Hsl, IntoColor, Srgb};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use rust_mc_proto::{DataReader, DataWriter, ProtocolError};
|
use rust_mc_proto::ProtocolError;
|
||||||
use serde_with::skip_serializing_none;
|
use serde_with::skip_serializing_none;
|
||||||
|
|
||||||
// Ошибки сервера
|
// Ошибки сервера
|
||||||
@ -52,62 +53,64 @@ pub struct TextComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TextComponent {
|
impl TextComponent {
|
||||||
|
pub fn new(text: String) -> Self {
|
||||||
|
Self {
|
||||||
|
text,
|
||||||
|
color: None,
|
||||||
|
bold: None,
|
||||||
|
italic: None,
|
||||||
|
underlined: None,
|
||||||
|
strikethrough: None,
|
||||||
|
obfuscated: None,
|
||||||
|
extra: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rainbow(text: String) -> TextComponent {
|
||||||
|
if text.is_empty() {
|
||||||
|
return TextComponent::new(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
let children = text.char_indices()
|
||||||
|
.map(|(i, c)| {
|
||||||
|
let hue = (i as f32) / (text.chars().count() as f32) * 360.0;
|
||||||
|
let hsl = Hsl::new(hue, 1.0, 0.5);
|
||||||
|
let rgb: Srgb = hsl.into_color();
|
||||||
|
let r = (rgb.red * 255.0).round() as u8;
|
||||||
|
let g = (rgb.green * 255.0).round() as u8;
|
||||||
|
let b = (rgb.blue * 255.0).round() as u8;
|
||||||
|
let mut component = TextComponent::new(c.to_string());
|
||||||
|
component.color = Some(format!("#{:02X}{:02X}{:02X}", r, g, b));
|
||||||
|
component
|
||||||
|
})
|
||||||
|
.collect::<Vec<TextComponent>>();
|
||||||
|
|
||||||
|
let mut parent = children[0].clone();
|
||||||
|
parent.extra = Some(children[1..].to_vec());
|
||||||
|
parent
|
||||||
|
}
|
||||||
|
|
||||||
pub fn builder() -> TextComponentBuilder {
|
pub fn builder() -> TextComponentBuilder {
|
||||||
TextComponentBuilder::new()
|
TextComponentBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string(self) -> Result<String, ServerError> {
|
pub fn as_nbt(self) -> Result<Vec<u8>, ServerError> {
|
||||||
self.try_into()
|
fastnbt::to_bytes(&self)
|
||||||
|
.map_err(|_| ServerError::SerTextComponent)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_string(text: String) -> Result<TextComponent, ServerError> {
|
pub fn from_nbt(bytes: &[u8]) -> Result<TextComponent, ServerError> {
|
||||||
Self::try_from(text)
|
fastnbt::from_bytes(bytes)
|
||||||
}
|
.map_err(|_| ServerError::DeTextComponent)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait WriteTextComponent {
|
pub fn as_json(self) -> Result<String, ServerError> {
|
||||||
fn write_text_component(&mut self, component: &TextComponent) -> Result<(), ServerError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: DataWriter> WriteTextComponent for T {
|
|
||||||
fn write_text_component(&mut self, component: &TextComponent) -> Result<(), ServerError> {
|
|
||||||
Ok(self.write_string(TryInto::<String>::try_into(component.clone())?.as_str())?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ReadTextComponent {
|
|
||||||
fn read_text_component(&mut self) -> Result<TextComponent, ServerError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: DataReader> ReadTextComponent for T {
|
|
||||||
fn read_text_component(&mut self) -> Result<TextComponent, ServerError> {
|
|
||||||
TextComponent::try_from(self.read_string()?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<String> for TextComponent {
|
|
||||||
type Error = ServerError;
|
|
||||||
|
|
||||||
fn try_into(self) -> Result<String, Self::Error> {
|
|
||||||
serde_json::to_string(&self)
|
serde_json::to_string(&self)
|
||||||
.map_err(|_| ServerError::SerTextComponent)
|
.map_err(|_| ServerError::SerTextComponent)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<String> for TextComponent {
|
pub fn from_json(text: &str) -> Result<TextComponent, ServerError> {
|
||||||
type Error = ServerError;
|
serde_json::from_str(text)
|
||||||
|
|
||||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
|
||||||
serde_json::from_str(&value)
|
|
||||||
.map_err(|_| ServerError::DeTextComponent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<&str> for TextComponent {
|
|
||||||
type Error = ServerError;
|
|
||||||
|
|
||||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
|
||||||
serde_json::from_str(&value)
|
|
||||||
.map_err(|_| ServerError::DeTextComponent)
|
.map_err(|_| ServerError::DeTextComponent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
125
src/main.rs
125
src/main.rs
@ -1,6 +1,6 @@
|
|||||||
use std::{env::args, io::{Read, Write}, net::TcpListener, path::PathBuf, sync::Arc, thread, time::Duration};
|
use std::{env::args, io::Read, net::TcpListener, path::PathBuf, sync::Arc, thread, time::Duration};
|
||||||
|
|
||||||
use config::ServerConfig;
|
use config::Config;
|
||||||
use context::{ClientContext, Listener, PacketHandler, ServerContext};
|
use context::{ClientContext, Listener, PacketHandler, ServerContext};
|
||||||
use rust_mc_proto::{DataReader, DataWriter, MinecraftConnection, Packet};
|
use rust_mc_proto::{DataReader, DataWriter, MinecraftConnection, Packet};
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ impl Listener for ExampleListener {
|
|||||||
.build()
|
.build()
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
.to_string()?
|
.as_json()?
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -89,7 +89,7 @@ fn main() {
|
|||||||
let config_path = PathBuf::from(args.get(0).unwrap_or(&"server.toml".to_string()));
|
let config_path = PathBuf::from(args.get(0).unwrap_or(&"server.toml".to_string()));
|
||||||
|
|
||||||
// Чтение конфига, если ошибка - выводим
|
// Чтение конфига, если ошибка - выводим
|
||||||
let config = match ServerConfig::load_from_file(config_path) {
|
let config = match Config::load_from_file(config_path) {
|
||||||
Some(config) => config,
|
Some(config) => config,
|
||||||
None => {
|
None => {
|
||||||
println!("Ошибка чтения конфигурации");
|
println!("Ошибка чтения конфигурации");
|
||||||
@ -113,12 +113,12 @@ fn main() {
|
|||||||
let server = Arc::new(server);
|
let server = Arc::new(server);
|
||||||
|
|
||||||
// Биндим сервер где надо
|
// Биндим сервер где надо
|
||||||
let Ok(listener) = TcpListener::bind(&server.config.host) else {
|
let Ok(listener) = TcpListener::bind(&server.config.bind.host) else {
|
||||||
println!("Не удалось забиндить сервер на {}", &server.config.host);
|
println!("Не удалось забиндить сервер на {}", &server.config.bind.host);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Сервер запущен на {}", &server.config.host);
|
println!("Сервер запущен на {}", &server.config.bind.host);
|
||||||
|
|
||||||
while let Ok((stream, addr)) = listener.accept() {
|
while let Ok((stream, addr)) = listener.accept() {
|
||||||
let server = server.clone();
|
let server = server.clone();
|
||||||
@ -128,8 +128,8 @@ fn main() {
|
|||||||
|
|
||||||
// Установка таймаутов на чтение и запись
|
// Установка таймаутов на чтение и запись
|
||||||
// По умолчанию пусть будет 5 секунд, надо будет сделать настройку через конфиг
|
// По умолчанию пусть будет 5 секунд, надо будет сделать настройку через конфиг
|
||||||
stream.set_read_timeout(Some(Duration::from_secs(server.config.timeout))).pohuy();
|
stream.set_read_timeout(Some(Duration::from_secs(server.config.bind.timeout))).pohuy();
|
||||||
stream.set_write_timeout(Some(Duration::from_secs(server.config.timeout))).pohuy();
|
stream.set_write_timeout(Some(Duration::from_secs(server.config.bind.timeout))).pohuy();
|
||||||
|
|
||||||
// Оборачиваем стрим в майнкрафт конекшн лично для нашего удовольствия
|
// Оборачиваем стрим в майнкрафт конекшн лично для нашего удовольствия
|
||||||
let conn = MinecraftConnection::new(stream);
|
let conn = MinecraftConnection::new(stream);
|
||||||
@ -214,22 +214,101 @@ fn handle_connection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
2 | 3 => { // Тип подключения - игра
|
2 => { // Тип подключения - игра
|
||||||
|
// Мы находимся в режиме Login
|
||||||
|
|
||||||
|
// Читаем пакет Login Start
|
||||||
|
let mut packet = client.conn().read_packet()?;
|
||||||
|
|
||||||
|
let player_name = packet.read_string()?;
|
||||||
|
let player_uuid = packet.read_uuid()?;
|
||||||
|
|
||||||
|
if client.server.config.server.online_mode {
|
||||||
|
// TODO: encryption packets
|
||||||
|
}
|
||||||
|
|
||||||
|
// Отправляем пакет Set Compression если сжатие указано
|
||||||
|
if let Some(threshold) = client.server.config.server.compression_threshold {
|
||||||
|
client.conn().write_packet(&Packet::build(0x03, |p| p.write_usize_varint(threshold))?)?;
|
||||||
|
client.conn().set_compression(Some(threshold)); // Устанавливаем сжатие на соединении
|
||||||
|
}
|
||||||
|
|
||||||
|
// Отправка пакета Login Success
|
||||||
|
client.conn().write_packet(&Packet::build(0x02, |p| {
|
||||||
|
p.write_uuid(&player_uuid)?;
|
||||||
|
p.write_string(&player_name)?;
|
||||||
|
p.write_varint(0)
|
||||||
|
})?)?;
|
||||||
|
|
||||||
|
let packet = client.conn().read_packet()?;
|
||||||
|
|
||||||
|
if packet.id() != 0x03 {
|
||||||
|
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет при ожидании Login Acknowledged")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Мы перешли в режим Configuration
|
||||||
|
|
||||||
|
let mut packet = client.conn().read_packet()?;
|
||||||
|
|
||||||
|
if packet.id() == 0x02 { // Пакет Serverbound Plugin Message
|
||||||
|
let identifier = packet.read_string()?;
|
||||||
|
let mut data = Vec::new();
|
||||||
|
packet.get_mut().read_to_end(&mut data).unwrap();
|
||||||
|
|
||||||
|
// TODO: Сделать запись всех этих полезных данных в клиент контекст
|
||||||
|
|
||||||
|
println!("got plugin message: {}", identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut packet = client.conn().read_packet()?;
|
||||||
|
|
||||||
|
if packet.id() == 0x00 { // Пакет Serverbound Plugin Message
|
||||||
|
let locale = packet.read_string()?; // for example: ru_RU
|
||||||
|
let view_distance = packet.read_signed_byte()?; // client-side render distance in chunks
|
||||||
|
let chat_mode = packet.read_varint()?; // 0: enabled, 1: commands only, 2: hidden. See Chat#Client chat mode for more information.
|
||||||
|
let chat_colors = packet.read_boolean()?; // this settings does nothing on client but can be used on serverside
|
||||||
|
let displayed_skin_parts = packet.read_byte()?; // bit mask https://minecraft.wiki/w/Java_Edition_protocol#Client_Information_(configuration)
|
||||||
|
let main_hand = packet.read_varint()?; // 0 for left and 1 for right
|
||||||
|
let enable_text_filtering = packet.read_boolean()?; // filtering text for profanity, always false for offline mode
|
||||||
|
let allow_server_listings = packet.read_boolean()?; // allows showing player in server listings in status
|
||||||
|
let particle_status = packet.read_varint()?; // 0 for all, 1 for decreased, 2 for minimal
|
||||||
|
|
||||||
|
// TODO: Сделать запись всех этих полезных данных в клиент контекст
|
||||||
|
|
||||||
|
println!("got client information:");
|
||||||
|
println!("locale: {locale}");
|
||||||
|
println!("view_distance: {view_distance}");
|
||||||
|
println!("chat_mode: {chat_mode}");
|
||||||
|
println!("chat_colors: {chat_colors}");
|
||||||
|
println!("displayed_skin_parts: {displayed_skin_parts}");
|
||||||
|
println!("main_hand: {main_hand}");
|
||||||
|
println!("enable_text_filtering: {enable_text_filtering}");
|
||||||
|
println!("allow_server_listings: {allow_server_listings}");
|
||||||
|
println!("particle_status: {particle_status}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Заюзать Listener'ы чтобы они подмешивали сюда чото
|
||||||
|
|
||||||
|
client.conn().write_packet(&Packet::empty(0x03))?;
|
||||||
|
|
||||||
|
let packet = client.conn().read_packet()?;
|
||||||
|
|
||||||
|
if packet.id() != 0x03 {
|
||||||
|
return Err(ServerError::UnknownPacket(format!("Неизвестный пакет при ожидании Acknowledge Finish Configuration")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Мы перешли в режим Play
|
||||||
|
|
||||||
// Отключение игрока с сообщением
|
// Отключение игрока с сообщением
|
||||||
// Заглушка так сказать
|
// Отправляет в формате NBT TAG_String (https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/NBT#Specification:string_tag)
|
||||||
let mut packet = Packet::empty(0x00);
|
client.conn().write_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
|
||||||
|
p.write_bytes(message.as_bytes())
|
||||||
|
})?)?;
|
||||||
|
|
||||||
packet.write_string(&TextComponent::builder()
|
// TODO: Сделать отправку пакетов Play
|
||||||
.text("This server is in developement!!")
|
|
||||||
.color("gold")
|
|
||||||
.bold(true)
|
|
||||||
.build()
|
|
||||||
.to_string()?)?;
|
|
||||||
|
|
||||||
client.conn().write_packet(&packet)?;
|
|
||||||
|
|
||||||
// TODO: Чтение Configuration (возможно с примешиванием Listener'ов)
|
|
||||||
// TODO: Обработчик пакетов Play (тоже трейт), который уже будет дергать Listener'ы
|
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ServerError::UnknownPacket(format!("Неизвестный NextState при рукопожатии")));
|
return Err(ServerError::UnknownPacket(format!("Неизвестный NextState при рукопожатии")));
|
||||||
|
Loading…
Reference in New Issue
Block a user