diff --git a/Cargo.lock b/Cargo.lock index c712ac17..0778b143 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,24 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -26,6 +44,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "anstream" version = "0.6.14" @@ -100,7 +124,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] @@ -111,7 +135,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] @@ -258,6 +282,46 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "clap_lex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" + [[package]] name = "colorchoice" version = "1.0.1" @@ -351,6 +415,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpufeatures" version = "0.2.11" @@ -400,6 +473,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "dary_heap" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" + [[package]] name = "dashmap" version = "6.0.1" @@ -474,15 +553,18 @@ version = "0.1.0" dependencies = [ "anyhow", "byteorder", + "clap", "config", "console-subscriber", "env_logger", "ferrumc_macros", "ferrumc_net", "ferrumc_utils", + "include-flate", "lazy_static", "log", "serde", + "spinners", "thiserror", "tokio", "toml", @@ -494,7 +576,7 @@ version = "0.1.0" dependencies = [ "ferrumc_utils", "quote", - "syn", + "syn 2.0.67", "tokio", ] @@ -652,6 +734,10 @@ name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", +] [[package]] name = "hdrhistogram" @@ -666,6 +752,18 @@ dependencies = [ "num-traits", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.3" @@ -748,6 +846,29 @@ dependencies = [ "tokio-io-timeout", ] +[[package]] +name = "include-flate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df49c16750695486c1f34de05da5b7438096156466e7f76c38fcdf285cf0113e" +dependencies = [ + "include-flate-codegen", + "lazy_static", + "libflate", +] + +[[package]] +name = "include-flate-codegen" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c5b246c6261be723b85c61ecf87804e8ea4a35cb68be0ff282ed84b95ffe7d7" +dependencies = [ + "libflate", + "proc-macro2", + "quote", + "syn 2.0.67", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -818,6 +939,30 @@ version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +[[package]] +name = "libflate" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d9dfdc14ea4ef0900c1cddbc8dcd553fbaacd8a4a282cf4018ae9dd04fb21e" +dependencies = [ + "adler32", + "core2", + "crc32fast", + "dary_heap", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d" +dependencies = [ + "core2", + "hashbrown 0.14.3", + "rle-decode-fast", +] + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -840,6 +985,12 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "matchers" version = "0.1.0" @@ -1013,7 +1164,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] @@ -1044,7 +1195,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] @@ -1094,7 +1245,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] @@ -1198,6 +1349,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rle-decode-fast" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" + [[package]] name = "ron" version = "0.8.1" @@ -1261,7 +1418,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] @@ -1338,6 +1495,56 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "spinners" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0ef947f358b9c238923f764c72a4a9d42f2d637c46e059dbd319d6e7cfb4f82" +dependencies = [ + "lazy_static", + "maplit", + "strum", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.67" @@ -1372,7 +1579,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] @@ -1432,7 +1639,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] @@ -1571,7 +1778,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.67", ] [[package]] @@ -1821,3 +2028,23 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.67", +] diff --git a/Cargo.toml b/Cargo.toml index b780b016..fb4214d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,6 @@ byteorder = "1.5.0" ferrumc_net = { path = "src/crates/ferrumc_net"} ferrumc_macros = { path = "src/crates/ferrumc_macros"} ferrumc_utils = { path = "src/crates/ferrumc_utils"} +clap = { version = "4.5.7", features = ["derive"] } +spinners = "4.1.1" +include-flate = "0.3.0" diff --git a/config.toml b/config.toml index 3d989866..9e11689a 100644 --- a/config.toml +++ b/config.toml @@ -1,4 +1,12 @@ +# The network address to bind to. Usually just 0.0.0.0 or 127.0.0.1 if you don't want to expose the server to the internet.s host = "0.0.0.0" +# The port to bind to. Default is 25565. port = 25565 +# The message displayed in the server list. motd = "A Minecraft Server written in Rust" -max_players = 20 \ No newline at end of file +# The maximum number of players that can be connected at once. +max_players = 20 +# How many network updates to process per second per user. 0 means no limit. +# This is the number of times per second the server will send updates to the client. +# Having this too low will cause noticable lag for clients but may improve server performance. +network_tick_rate = 0 \ No newline at end of file diff --git a/src/crates/ferrumc_net/src/lib.rs b/src/crates/ferrumc_net/src/lib.rs index 1b95feb7..f3915027 100644 --- a/src/crates/ferrumc_net/src/lib.rs +++ b/src/crates/ferrumc_net/src/lib.rs @@ -12,6 +12,7 @@ use rand::random; use tokio::io::AsyncReadExt; use tokio::io::AsyncWriteExt; use tokio::sync::RwLock; +use ferrumc_utils::config::get_global_config; use ferrumc_utils::encoding::varint::read_varint; use ferrumc_utils::prelude::*; @@ -166,6 +167,14 @@ pub async fn manage_conn(conn: &mut Arc>) -> Result<()> { conn.write().await.socket.shutdown().await?; break; } + + tokio::time::sleep( + if get_global_config().network_tick_rate > 0 { + std::time::Duration::from_millis(1000 / get_global_config().network_tick_rate as u64) + } else { + std::time::Duration::from_millis(0) + } + ).await; } Ok(()) } diff --git a/src/crates/ferrumc_utils/src/config.rs b/src/crates/ferrumc_utils/src/config.rs index efa66f65..da798f5b 100644 --- a/src/crates/ferrumc_utils/src/config.rs +++ b/src/crates/ferrumc_utils/src/config.rs @@ -15,6 +15,7 @@ pub struct ServerConfig { pub port: u32, pub motd: String, pub max_players: u32, + pub network_tick_rate: u32, } #[derive(Debug, Serialize, Deserialize)] @@ -110,6 +111,7 @@ impl Default for ServerConfig { port: DEFAULT_SERVER_PORT, motd: DEFAULT_MOTD.to_string(), max_players: DEFAULT_MAX_PLAYERS, + network_tick_rate: 0, } } } diff --git a/src/main.rs b/src/main.rs index 58757afa..a7e81f35 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,11 @@ #![feature(box_into_inner)] +#![feature(fs_try_exists)] +use std::fs; use std::sync::Arc; +use clap::{Parser}; + use log::{debug, info, trace}; use tokio::net::TcpListener; use tokio::sync::RwLock; @@ -11,12 +15,30 @@ use ferrumc_utils::prelude::*; mod prelude; mod tests; mod utils; +mod setup; type SafeConfig = Arc>; + +#[derive(Parser)] +#[command(version, about, long_about = None)] +struct Cli { + #[clap(long, default_value = "false")] + setup: bool, +} + + #[tokio::main] async fn main() -> Result<()> { - ferrumc_net::setup_tracer(); + + let args = Cli::parse(); + + // run setup if the flag is set or the config file does not exist in release mode + if args.setup || (!fs::try_exists("config.toml")? && !cfg!(debug_assertions)) { + setup::setup().await?; + return Ok(()) + } + utils::setup_logger(); info!("Initializing server..."); @@ -57,21 +79,4 @@ async fn start_server(config: SafeConfig) -> Result<()> { tokio::task::spawn(ferrumc_net::handle_connection(socket)); } -} - -/*async fn handle_handshake(mut cursor: Cursor>) -> Result<()> { - trace!("Handling handshake packet"); - - let protocol_version = ferrumc_utils::encoding::varint::read_varint(&mut cursor).await?; - let server_address = ferrumc_utils::encoding::string::read_string(&mut cursor).await?; - let server_port = cursor.read_u16::().unwrap(); - let next_state = ferrumc_utils::encoding::varint::read_varint(&mut cursor).await?; - - trace!("Protocol Version: {}", protocol_version); - trace!("Server Address: {}", server_address); - trace!("Server Port: {}", server_port); - trace!("Next State: {}", next_state); - - Ok(()) -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/src/setup.rs b/src/setup.rs new file mode 100644 index 00000000..0560f097 --- /dev/null +++ b/src/setup.rs @@ -0,0 +1,25 @@ +use tokio::fs; +use std::env::current_exe; +use ferrumc_utils::error::Error; +use spinners::{Spinner, Spinners}; +use include_flate::flate; + +flate!(pub static BASE_CONFIG: [u8] from "config.toml"); + +pub(crate) async fn setup() -> Result<(), Error> { + let mut sp = Spinner::new(Spinners::Dots, "Setting up files...".into()); + let exe = current_exe()?; + let dir = exe.parent().unwrap(); + fs::write(dir.join("config.toml"), BASE_CONFIG.to_vec()).await?; + fs::create_dir(dir.join("logs")).await?; + fs::create_dir(dir.join("data")).await?; + fs::create_dir(dir.join("plugins")).await?; + fs::write(dir.join("plugins").join("README.txt"), "Unfortunately plugins are not yet available").await?; + fs::create_dir(dir.join("worlds")).await?; + sp.stop(); + for _ in 0..36 { + print!("{}", 8u8 as char) + } + println!("Files setup successfully!"); + Ok(()) +} \ No newline at end of file