From 3159e61c05f44b8eadbbc8c5afef0ce930de181b Mon Sep 17 00:00:00 2001 From: StripedMonkey Date: Wed, 28 Aug 2024 18:56:35 -0400 Subject: [PATCH 01/17] create rust-toolchain.toml --- rust-toolchain.toml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000..438956093 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,7 @@ +[toolchain] +# Anything in the latest stable version of rust is fine to use. +channel = "stable" +targets = [ + "x86_64-unknown-linux-gnu", + "x86_64-pc-windows-msvc", +] \ No newline at end of file From 2c192b568959dbfaef0a6b397091588e807ff3ca Mon Sep 17 00:00:00 2001 From: Noah Date: Sat, 31 Aug 2024 11:53:45 -0400 Subject: [PATCH 02/17] add requested targets --- rust-toolchain.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 438956093..c4bd27c80 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,6 +2,8 @@ # Anything in the latest stable version of rust is fine to use. channel = "stable" targets = [ - "x86_64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", "x86_64-pc-windows-msvc", -] \ No newline at end of file + "x86_64-unknown-linux-gnu", +] From 3535d2cda1ad29ab7e9536aac8e3aa868dab2a41 Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Thu, 29 Aug 2024 16:52:22 +0200 Subject: [PATCH 03/17] Fixed new clippy lint --- pumpkin/src/config/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index cc47d9772..d5e1876c5 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -14,10 +14,12 @@ pub mod resource_pack; /// Current Config version of the Base Config const CURRENT_BASE_VERSION: &str = "1.0.0"; -#[derive(Deserialize, Serialize)] -/// The idea is that Pumpkin should very customizable, You can Enable or Disable Features depending on your needs. +/// The idea is that Pumpkin should very customizable. +/// You can Enable or Disable Features depending on your needs. +/// /// This also allows you get some Performance or Resource boosts. /// Important: The Configuration should match Vanilla by default +#[derive(Deserialize, Serialize)] pub struct AdvancedConfiguration { pub proxy: ProxyConfig, pub authentication: AuthenticationConfig, From ff68b5cac503412a97d84982ded562f9d7b9167c Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Sat, 31 Aug 2024 18:49:23 +0200 Subject: [PATCH 04/17] Removed manual Default implementation --- pumpkin/src/config/mod.rs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index d5e1876c5..e98b78dc7 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -19,7 +19,7 @@ const CURRENT_BASE_VERSION: &str = "1.0.0"; /// /// This also allows you get some Performance or Resource boosts. /// Important: The Configuration should match Vanilla by default -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, Default)] pub struct AdvancedConfiguration { pub proxy: ProxyConfig, pub authentication: AuthenticationConfig, @@ -111,21 +111,6 @@ impl Default for CompressionConfig { } } -/// Important: The Configuration should match Vanilla by default -impl Default for AdvancedConfiguration { - fn default() -> Self { - Self { - proxy: ProxyConfig::default(), - authentication: AuthenticationConfig::default(), - commands: CommandsConfig::default(), - packet_compression: CompressionConfig::default(), - resource_pack: ResourcePackConfig::default(), - rcon: RCONConfig::default(), - pvp: PVPConfig::default(), - } - } -} - #[derive(Serialize, Deserialize)] pub struct BasicConfiguration { /// A version identifier for the configuration format. From d57d9ffdcc9b8a5843c5ed00b54d6102a0b10341 Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Thu, 29 Aug 2024 16:56:35 +0200 Subject: [PATCH 05/17] Use proper IP Address abstraction instead of using format!() --- pumpkin/src/config/mod.rs | 19 ++++++++----------- pumpkin/src/main.rs | 9 +-------- pumpkin/src/rcon/mod.rs | 5 +---- 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index e98b78dc7..fffe2c1a0 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -1,9 +1,11 @@ -use std::path::Path; - use auth_config::AuthenticationConfig; use proxy::ProxyConfig; use resource_pack::ResourcePackConfig; use serde::{Deserialize, Serialize}; +use std::{ + net::{Ipv4Addr, SocketAddr}, + path::Path, +}; use crate::{entity::player::GameMode, server::Difficulty}; @@ -33,8 +35,7 @@ pub struct AdvancedConfiguration { #[derive(Deserialize, Serialize, Clone)] pub struct RCONConfig { pub enabled: bool, - pub ip: String, - pub port: u16, + pub address: SocketAddr, pub password: String, } @@ -42,8 +43,7 @@ impl Default for RCONConfig { fn default() -> Self { Self { enabled: false, - ip: "0.0.0.0".to_string(), - port: 25575, + address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25575), password: "".to_string(), } } @@ -116,9 +116,7 @@ pub struct BasicConfiguration { /// A version identifier for the configuration format. pub config_version: String, /// The address to bind the server to. - pub server_address: String, - /// The port to listen on. - pub server_port: u16, + pub server_address: SocketAddr, /// The seed for world generation. pub seed: String, /// The maximum number of players allowed on the server. @@ -147,8 +145,7 @@ impl Default for BasicConfiguration { fn default() -> Self { Self { config_version: CURRENT_BASE_VERSION.to_string(), - server_address: "0.0.0.0".to_string(), - server_port: 25565, + server_address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25565), seed: "".to_string(), max_players: 100000, view_distance: 10, diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index 56281f274..d586b6040 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -74,14 +74,7 @@ fn main() -> io::Result<()> { let mut events = Events::with_capacity(128); // Setup the TCP server socket. - - let addr = format!( - "{}:{}", - basic_config.server_address, basic_config.server_port - ) - .parse() - .unwrap(); - + let addr = basic_config.server_address; let mut listener = TcpListener::bind(addr)?; // Register the server with poll we can receive events for it. diff --git a/pumpkin/src/rcon/mod.rs b/pumpkin/src/rcon/mod.rs index e6a94fdf8..3f20ffd54 100644 --- a/pumpkin/src/rcon/mod.rs +++ b/pumpkin/src/rcon/mod.rs @@ -35,11 +35,8 @@ impl RCONServer { server: Arc>, ) -> Result { assert!(config.enabled, "RCON is not enabled"); - let addr = format!("{}:{}", config.ip, config.port) - .parse() - .expect("Failed to parse RCON address"); let mut poll = Poll::new().unwrap(); - let mut listener = TcpListener::bind(addr).unwrap(); + let mut listener = TcpListener::bind(config.address).unwrap(); poll.registry() .register(&mut listener, SERVER, Interest::READABLE) From d2924d463255b6638912fd68583801709205edfa Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Thu, 29 Aug 2024 19:02:10 +0200 Subject: [PATCH 06/17] Moved `auth_config` to `auth` Make it consistent with `proxy` and `resource_pack` --- pumpkin/src/client/authentication.rs | 2 +- pumpkin/src/config/{auth_config.rs => auth.rs} | 0 pumpkin/src/config/mod.rs | 5 +++-- 3 files changed, 4 insertions(+), 3 deletions(-) rename pumpkin/src/config/{auth_config.rs => auth.rs} (100%) diff --git a/pumpkin/src/client/authentication.rs b/pumpkin/src/client/authentication.rs index d841756a3..44f2054dd 100644 --- a/pumpkin/src/client/authentication.rs +++ b/pumpkin/src/client/authentication.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use uuid::Uuid; -use crate::{config::auth_config::TextureConfig, server::Server}; +use crate::{config::auth::TextureConfig, server::Server}; #[derive(Deserialize, Clone, Debug)] #[allow(non_snake_case)] diff --git a/pumpkin/src/config/auth_config.rs b/pumpkin/src/config/auth.rs similarity index 100% rename from pumpkin/src/config/auth_config.rs rename to pumpkin/src/config/auth.rs diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index fffe2c1a0..68679b9b6 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -1,4 +1,3 @@ -use auth_config::AuthenticationConfig; use proxy::ProxyConfig; use resource_pack::ResourcePackConfig; use serde::{Deserialize, Serialize}; @@ -9,10 +8,12 @@ use std::{ use crate::{entity::player::GameMode, server::Difficulty}; -pub mod auth_config; +pub mod auth; pub mod proxy; pub mod resource_pack; +use auth::AuthenticationConfig; + /// Current Config version of the Base Config const CURRENT_BASE_VERSION: &str = "1.0.0"; From 003219d3e8faf093c4effd84639bf3acc582fa13 Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Thu, 29 Aug 2024 20:28:25 +0200 Subject: [PATCH 07/17] Sorted main.rs inputs --- pumpkin/src/main.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index d586b6040..aa57f5ed9 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -6,16 +6,13 @@ compile_error!("Compiling for WASI targets is not supported!"); use mio::net::TcpListener; use mio::{Events, Interest, Poll, Token}; -use std::io::{self}; - -use client::Client; -use commands::handle_command; -use config::AdvancedConfiguration; use std::collections::HashMap; +use std::io::{self}; -use client::interrupted; -use config::BasicConfiguration; +use client::{interrupted, Client}; +use commands::handle_command; +use config::{AdvancedConfiguration, BasicConfiguration}; use server::Server; // Setup some tokens to allow us to identify which event is for which socket. From a6cb88b48fb10a61979db142ea7b7220de18fed6 Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Thu, 29 Aug 2024 20:28:51 +0200 Subject: [PATCH 08/17] Added LoadConfiguration trait. De-duplicates code from both BasicConfiguration and AdvancedConfiguration. Allow config to fail writing. (On e.g. immutable linux distros) --- pumpkin/src/config/mod.rs | 82 ++++++++++++++++++++++++--------------- pumpkin/src/main.rs | 6 +-- 2 files changed, 54 insertions(+), 34 deletions(-) diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index 68679b9b6..9baa3fad4 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -1,7 +1,9 @@ +use log::warn; use proxy::ProxyConfig; use resource_pack::ResourcePackConfig; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{ + fs, net::{Ipv4Addr, SocketAddr}, path::Path, }; @@ -162,44 +164,62 @@ impl Default for BasicConfiguration { } } -impl AdvancedConfiguration { - pub fn load>(path: P) -> AdvancedConfiguration { - if path.as_ref().exists() { - let toml = std::fs::read_to_string(path).expect("Couldn't read configuration"); - let config: AdvancedConfiguration = - toml::from_str(toml.as_str()).expect("Couldn't parse features.toml, Probably old config, Replacing with a new one or just delete it"); - config.validate(); - config +pub trait LoadConfiguration { + fn load() -> Self + where + Self: Sized + Default + Serialize + DeserializeOwned, + { + let path = Self::get_path(); + + let config = if path.exists() { + let file_content = fs::read_to_string(path) + .unwrap_or_else(|_| panic!("Couldn't read configuration file at {:?}", path)); + + toml::from_str(&file_content).unwrap_or_else(|err| { + panic!( + "Couldn't parse config at {:?}. Reason: {}", + path, + err.message() + ) + }) } else { - let config = AdvancedConfiguration::default(); - let toml = toml::to_string(&config).expect("Couldn't create toml!"); - std::fs::write(path, toml).expect("Couldn't save configuration"); - config.validate(); - config - } + let content = Self::default(); + + if let Err(err) = fs::write(path, toml::to_string(&content).unwrap()) { + warn!( + "Couldn't write default config to {:?}. Reason: {}", + path, err + ); + } + + content + }; + + config.validate(); + config } - pub fn validate(&self) { + + fn get_path() -> &'static Path; + + fn validate(&self); +} + +impl LoadConfiguration for AdvancedConfiguration { + fn get_path() -> &'static Path { + Path::new("features.toml") + } + + fn validate(&self) { self.resource_pack.validate() } } -impl BasicConfiguration { - pub fn load>(path: P) -> BasicConfiguration { - if path.as_ref().exists() { - let toml = std::fs::read_to_string(path).expect("Couldn't read configuration"); - let config: BasicConfiguration = toml::from_str(toml.as_str()).expect("Couldn't parse configuration.toml, Probably old config, Replacing with a new one or just delete it"); - config.validate(); - config - } else { - let config = BasicConfiguration::default(); - let toml = toml::to_string(&config).expect("Couldn't create toml!"); - std::fs::write(path, toml).expect("Couldn't save configuration"); - config.validate(); - config - } +impl LoadConfiguration for BasicConfiguration { + fn get_path() -> &'static Path { + Path::new("configuration.toml") } - pub fn validate(&self) { + fn validate(&self) { assert_eq!( self.config_version, CURRENT_BASE_VERSION, "Config version does not match used Config version. Please update your config" diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index aa57f5ed9..9f685a84a 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -12,7 +12,7 @@ use std::io::{self}; use client::{interrupted, Client}; use commands::handle_command; -use config::{AdvancedConfiguration, BasicConfiguration}; +use config::{AdvancedConfiguration, BasicConfiguration, LoadConfiguration}; use server::Server; // Setup some tokens to allow us to identify which event is for which socket. @@ -61,9 +61,9 @@ fn main() -> io::Result<()> { use std::time::Instant; let time = Instant::now(); - let basic_config = BasicConfiguration::load("configuration.toml"); + let basic_config = BasicConfiguration::load(); - let advanced_configuration = AdvancedConfiguration::load("features.toml"); + let advanced_configuration = AdvancedConfiguration::load(); // Create a poll instance. let mut poll = Poll::new()?; From e48ca3b99f66b6721579491747793ae755be41cb Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Sat, 31 Aug 2024 13:58:42 +0200 Subject: [PATCH 09/17] Moved configuration structs into own files - PVPConfiguration - RCONConfiguration - CompressionConfiguration - CommandsConfiguration --- pumpkin/src/config/commands.rs | 14 +++++ pumpkin/src/config/compression.rs | 24 +++++++++ pumpkin/src/config/mod.rs | 90 ++++--------------------------- pumpkin/src/config/pvp.rs | 27 ++++++++++ pumpkin/src/config/rcon.rs | 20 +++++++ 5 files changed, 95 insertions(+), 80 deletions(-) create mode 100644 pumpkin/src/config/commands.rs create mode 100644 pumpkin/src/config/compression.rs create mode 100644 pumpkin/src/config/pvp.rs create mode 100644 pumpkin/src/config/rcon.rs diff --git a/pumpkin/src/config/commands.rs b/pumpkin/src/config/commands.rs new file mode 100644 index 000000000..94ee4d8c2 --- /dev/null +++ b/pumpkin/src/config/commands.rs @@ -0,0 +1,14 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +pub struct CommandsConfig { + /// Are commands from the Console accepted ? + pub use_console: bool, + // TODO: commands... +} + +impl Default for CommandsConfig { + fn default() -> Self { + Self { use_console: true } + } +} diff --git a/pumpkin/src/config/compression.rs b/pumpkin/src/config/compression.rs new file mode 100644 index 000000000..544c8d31d --- /dev/null +++ b/pumpkin/src/config/compression.rs @@ -0,0 +1,24 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +// Packet compression +pub struct CompressionConfig { + /// Is compression enabled ? + pub enabled: bool, + /// The compression threshold used when compression is enabled + pub compression_threshold: u32, + /// A value between 0..9 + /// 1 = Optimize for the best speed of encoding. + /// 9 = Optimize for the size of data being encoded. + pub compression_level: u32, +} + +impl Default for CompressionConfig { + fn default() -> Self { + Self { + enabled: true, + compression_threshold: 256, + compression_level: 4, + } + } +} diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index 9baa3fad4..50c40b977 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -14,7 +14,16 @@ pub mod auth; pub mod proxy; pub mod resource_pack; -use auth::AuthenticationConfig; +mod commands; +mod compression; +mod pvp; +mod rcon; + +pub use auth::AuthenticationConfig; +pub use commands::CommandsConfig; +pub use compression::CompressionConfig; +pub use pvp::PVPConfig; +pub use rcon::RCONConfig; /// Current Config version of the Base Config const CURRENT_BASE_VERSION: &str = "1.0.0"; @@ -35,85 +44,6 @@ pub struct AdvancedConfiguration { pub pvp: PVPConfig, } -#[derive(Deserialize, Serialize, Clone)] -pub struct RCONConfig { - pub enabled: bool, - pub address: SocketAddr, - pub password: String, -} - -impl Default for RCONConfig { - fn default() -> Self { - Self { - enabled: false, - address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25575), - password: "".to_string(), - } - } -} - -#[derive(Deserialize, Serialize)] -pub struct CommandsConfig { - /// Are commands from the Console accepted ? - pub use_console: bool, - // TODO: commands... -} - -impl Default for CommandsConfig { - fn default() -> Self { - Self { use_console: true } - } -} - -#[derive(Deserialize, Serialize)] -pub struct PVPConfig { - /// Is PVP enabled ? - pub enabled: bool, - /// Do we want to have the Red hurt animation & fov bobbing - pub hurt_animation: bool, - /// Should players in creative be protected against PVP - pub protect_creative: bool, - /// Has PVP Knockback? - pub knockback: bool, - /// Should player swing when attacking? - pub swing: bool, -} - -impl Default for PVPConfig { - fn default() -> Self { - Self { - enabled: true, - hurt_animation: true, - protect_creative: true, - knockback: true, - swing: true, - } - } -} - -#[derive(Deserialize, Serialize)] -// Packet compression -pub struct CompressionConfig { - /// Is compression enabled ? - pub enabled: bool, - /// The compression threshold used when compression is enabled - pub compression_threshold: u32, - /// A value between 0..9 - /// 1 = Optimize for the best speed of encoding. - /// 9 = Optimize for the size of data being encoded. - pub compression_level: u32, -} - -impl Default for CompressionConfig { - fn default() -> Self { - Self { - enabled: true, - compression_threshold: 256, - compression_level: 4, - } - } -} - #[derive(Serialize, Deserialize)] pub struct BasicConfiguration { /// A version identifier for the configuration format. diff --git a/pumpkin/src/config/pvp.rs b/pumpkin/src/config/pvp.rs new file mode 100644 index 000000000..cfbddc6c4 --- /dev/null +++ b/pumpkin/src/config/pvp.rs @@ -0,0 +1,27 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +pub struct PVPConfig { + /// Is PVP enabled ? + pub enabled: bool, + /// Do we want to have the Red hurt animation & fov bobbing + pub hurt_animation: bool, + /// Should players in creative be protected against PVP + pub protect_creative: bool, + /// Has PVP Knockback? + pub knockback: bool, + /// Should player swing when attacking? + pub swing: bool, +} + +impl Default for PVPConfig { + fn default() -> Self { + Self { + enabled: true, + hurt_animation: true, + protect_creative: true, + knockback: true, + swing: true, + } + } +} diff --git a/pumpkin/src/config/rcon.rs b/pumpkin/src/config/rcon.rs new file mode 100644 index 000000000..af5aa6ac0 --- /dev/null +++ b/pumpkin/src/config/rcon.rs @@ -0,0 +1,20 @@ +use std::net::{Ipv4Addr, SocketAddr}; + +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Clone)] +pub struct RCONConfig { + pub enabled: bool, + pub address: SocketAddr, + pub password: String, +} + +impl Default for RCONConfig { + fn default() -> Self { + Self { + enabled: false, + address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25575), + password: "".to_string(), + } + } +} From bb543b7178860bb297549f9c77403988d055ecae Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Sat, 31 Aug 2024 17:24:36 +0200 Subject: [PATCH 10/17] Moved configuration to LazyLock --- pumpkin/src/client/authentication.rs | 13 ++++++------- pumpkin/src/client/client_packet.rs | 26 +++++++++++--------------- pumpkin/src/client/player_packet.rs | 5 +++-- pumpkin/src/config/mod.rs | 8 +++++++- pumpkin/src/main.rs | 18 ++++++------------ pumpkin/src/server.rs | 15 ++++++--------- 6 files changed, 39 insertions(+), 46 deletions(-) diff --git a/pumpkin/src/client/authentication.rs b/pumpkin/src/client/authentication.rs index 44f2054dd..13dc427fa 100644 --- a/pumpkin/src/client/authentication.rs +++ b/pumpkin/src/client/authentication.rs @@ -8,7 +8,10 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use uuid::Uuid; -use crate::{config::auth::TextureConfig, server::Server}; +use crate::{ + config::{auth::TextureConfig, ADVANCED_CONFIG}, + server::Server, +}; #[derive(Deserialize, Clone, Debug)] #[allow(non_snake_case)] @@ -52,13 +55,9 @@ pub async fn authenticate( ip: &IpAddr, server: &mut Server, ) -> Result { - assert!(server.advanced_config.authentication.enabled); + assert!(ADVANCED_CONFIG.authentication.enabled); assert!(server.auth_client.is_some()); - let address = if server - .advanced_config - .authentication - .prevent_proxy_connections - { + let address = if ADVANCED_CONFIG.authentication.prevent_proxy_connections { format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}&ip={ip}") } else { format!("https://sessionserver.mojang.com/session/minecraft/hasJoined?username={username}&serverId={server_hash}") diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index 7ac629f5d..855c12d57 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -19,6 +19,7 @@ use sha1::{Digest, Sha1}; use crate::{ client::authentication::{self, GameProfile}, + config::{ADVANCED_CONFIG, BASIC_CONFIG}, entity::player::{ChatMode, Hand}, proxy::velocity::velocity_login, server::{Server, CURRENT_MC_VERSION}, @@ -81,7 +82,7 @@ impl Client { properties: vec![], profile_actions: None, }); - let proxy = &server.advanced_config.proxy; + let proxy = &ADVANCED_CONFIG.proxy; if proxy.enabled { if proxy.velocity.enabled { velocity_login(self) @@ -96,7 +97,7 @@ impl Client { "", public_key_der, &verify_token, - server.base_config.online_mode, // TODO + BASIC_CONFIG.online_mode, // TODO ); self.send_packet(&packet); } @@ -114,7 +115,7 @@ impl Client { self.enable_encryption(&shared_secret) .unwrap_or_else(|e| self.kick(&e.to_string())); - if server.base_config.online_mode { + if BASIC_CONFIG.online_mode { let hash = Sha1::new() .chain_update(&shared_secret) .chain_update(&server.public_key_der) @@ -132,8 +133,7 @@ impl Client { Ok(p) => { // Check if player should join if let Some(p) = &p.profile_actions { - if !server - .advanced_config + if !ADVANCED_CONFIG .authentication .player_profile .allow_banned_players @@ -142,8 +142,7 @@ impl Client { self.kick("Your account can't join"); } } else { - for allowed in server - .advanced_config + for allowed in ADVANCED_CONFIG .authentication .player_profile .allowed_actions @@ -162,16 +161,13 @@ impl Client { } for ele in self.gameprofile.as_ref().unwrap().properties.clone() { // todo, use this - unpack_textures(ele, &server.advanced_config.authentication.textures); + unpack_textures(ele, &ADVANCED_CONFIG.authentication.textures); } // enable compression - if server.advanced_config.packet_compression.enabled { - let threshold = server - .advanced_config - .packet_compression - .compression_threshold; - let level = server.advanced_config.packet_compression.compression_level; + if ADVANCED_CONFIG.packet_compression.enabled { + let threshold = ADVANCED_CONFIG.packet_compression.compression_threshold; + let level = ADVANCED_CONFIG.packet_compression.compression_level; self.send_packet(&CSetCompression::new(threshold.into())); self.set_compression(Some((threshold, level))); } @@ -199,7 +195,7 @@ impl Client { self.connection_state = ConnectionState::Config; server.send_brand(self); - let resource_config = &server.advanced_config.resource_pack; + let resource_config = &ADVANCED_CONFIG.resource_pack; if resource_config.enabled { let prompt_message = if resource_config.prompt_message.is_empty() { None diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index be6e08ccc..15fe31477 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -2,6 +2,7 @@ use std::f32::consts::PI; use crate::{ commands::{handle_command, CommandSender}, + config::ADVANCED_CONFIG, entity::player::{ChatMode, GameMode, Hand, Player}, server::Server, util::math::wrap_degrees, @@ -313,7 +314,7 @@ impl Player { } } - pub async fn handle_interact(&mut self, server: &mut Server, interact: SInteract) { + pub async fn handle_interact(&mut self, _: &mut Server, interact: SInteract) { let sneaking = interact.sneaking; if self.sneaking != sneaking { self.set_sneaking(sneaking).await; @@ -323,7 +324,7 @@ impl Player { ActionType::Attack => { let entity_id = interact.entity_id; // TODO: do validation and stuff - let config = &server.advanced_config.pvp; + let config = &ADVANCED_CONFIG.pvp; if config.enabled { let world = self.world.clone(); let world = world.lock().await; diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index 50c40b977..55369279f 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -6,6 +6,7 @@ use std::{ fs, net::{Ipv4Addr, SocketAddr}, path::Path, + sync::LazyLock, }; use crate::{entity::player::GameMode, server::Difficulty}; @@ -28,6 +29,11 @@ pub use rcon::RCONConfig; /// Current Config version of the Base Config const CURRENT_BASE_VERSION: &str = "1.0.0"; +pub static ADVANCED_CONFIG: LazyLock = + LazyLock::new(AdvancedConfiguration::load); + +pub static BASIC_CONFIG: LazyLock = LazyLock::new(BasicConfiguration::load); + /// The idea is that Pumpkin should very customizable. /// You can Enable or Disable Features depending on your needs. /// @@ -94,7 +100,7 @@ impl Default for BasicConfiguration { } } -pub trait LoadConfiguration { +trait LoadConfiguration { fn load() -> Self where Self: Sized + Default + Serialize + DeserializeOwned, diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index 9f685a84a..4acac485b 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -12,7 +12,6 @@ use std::io::{self}; use client::{interrupted, Client}; use commands::handle_command; -use config::{AdvancedConfiguration, BasicConfiguration, LoadConfiguration}; use server::Server; // Setup some tokens to allow us to identify which event is for which socket. @@ -30,6 +29,7 @@ pub mod world; fn main() -> io::Result<()> { use std::sync::{Arc, Mutex}; + use config::{ADVANCED_CONFIG, BASIC_CONFIG}; use entity::player::Player; use pumpkin_core::text::{color::NamedColor, TextComponent}; use rcon::RCONServer; @@ -61,9 +61,6 @@ fn main() -> io::Result<()> { use std::time::Instant; let time = Instant::now(); - let basic_config = BasicConfiguration::load(); - - let advanced_configuration = AdvancedConfiguration::load(); // Create a poll instance. let mut poll = Poll::new()?; @@ -71,7 +68,7 @@ fn main() -> io::Result<()> { let mut events = Events::with_capacity(128); // Setup the TCP server socket. - let addr = basic_config.server_address; + let addr = BASIC_CONFIG.server_address; let mut listener = TcpListener::bind(addr)?; // Register the server with poll we can receive events for it. @@ -81,16 +78,13 @@ fn main() -> io::Result<()> { // Unique token for each incoming connection. let mut unique_token = Token(SERVER.0 + 1); - let use_console = advanced_configuration.commands.use_console; - let rcon = advanced_configuration.rcon.clone(); + let use_console = ADVANCED_CONFIG.commands.use_console; + let rcon = ADVANCED_CONFIG.rcon.clone(); let mut clients: HashMap = HashMap::new(); let mut players: HashMap, Arc>> = HashMap::new(); - let server = Arc::new(tokio::sync::Mutex::new(Server::new(( - basic_config, - advanced_configuration, - )))); + let server = Arc::new(tokio::sync::Mutex::new(Server::new())); log::info!("Started Server took {}ms", time.elapsed().as_millis()); log::info!("You now can connect to the server, Listening on {}", addr); @@ -204,7 +198,7 @@ fn main() -> io::Result<()> { server.add_player(token.clone(), client).await; players.insert(token, player.clone()); let mut world = world.lock().await; - world.spawn_player(&server.base_config, player).await; + world.spawn_player(&BASIC_CONFIG, player).await; } } } diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 582d4e992..8a2bb136a 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -25,7 +25,7 @@ use serde::{Deserialize, Serialize}; use crate::{ client::Client, - config::{AdvancedConfiguration, BasicConfiguration}, + config::{BasicConfiguration, BASIC_CONFIG}, entity::player::{GameMode, Player}, world::World, }; @@ -52,16 +52,15 @@ pub struct Server { pub cached_registry: Vec, entity_id: AtomicI32, - pub base_config: BasicConfiguration, - pub advanced_config: AdvancedConfiguration, /// Used for Authentication, None is Online mode is disabled pub auth_client: Option, } impl Server { - pub fn new(config: (BasicConfiguration, AdvancedConfiguration)) -> Self { - let status_response = Self::build_response(&config.0); + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + let status_response = Self::build_response(&BASIC_CONFIG); let status_response_json = serde_json::to_string(&status_response) .expect("Failed to parse Status response into JSON"); let cached_server_brand = Self::build_brand(); @@ -75,7 +74,7 @@ impl Server { &private_key.e().to_bytes_be(), ) .into_boxed_slice(); - let auth_client = if config.0.online_mode { + let auth_client = if BASIC_CONFIG.online_mode { Some( reqwest::Client::builder() .timeout(Duration::from_millis(5000)) @@ -106,9 +105,7 @@ impl Server { status_response, status_response_json, public_key_der, - base_config: config.0, auth_client, - advanced_config: config.1, } } @@ -118,7 +115,7 @@ impl Server { client: Client, ) -> (Arc>, Arc>) { let entity_id = self.new_entity_id(); - let gamemode = match self.base_config.default_gamemode { + let gamemode = match BASIC_CONFIG.default_gamemode { GameMode::Undefined => GameMode::Survival, game_mode => game_mode, }; From 6740e717f7cf94c1d91dee9d647d9bea28d10e1e Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Sat, 31 Aug 2024 17:38:49 +0200 Subject: [PATCH 11/17] Reordered Imports --- pumpkin/src/config/mod.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index 55369279f..5c854116d 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -1,7 +1,6 @@ use log::warn; -use proxy::ProxyConfig; -use resource_pack::ResourcePackConfig; use serde::{de::DeserializeOwned, Deserialize, Serialize}; + use std::{ fs, net::{Ipv4Addr, SocketAddr}, @@ -15,17 +14,20 @@ pub mod auth; pub mod proxy; pub mod resource_pack; -mod commands; -mod compression; -mod pvp; -mod rcon; - pub use auth::AuthenticationConfig; pub use commands::CommandsConfig; pub use compression::CompressionConfig; pub use pvp::PVPConfig; pub use rcon::RCONConfig; +mod commands; +mod compression; +mod pvp; +mod rcon; + +use proxy::ProxyConfig; +use resource_pack::ResourcePackConfig; + /// Current Config version of the Base Config const CURRENT_BASE_VERSION: &str = "1.0.0"; From 2fbf450ed35eb1cc16cdaeef6a8cf54e91f7368b Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Sat, 31 Aug 2024 18:16:15 +0200 Subject: [PATCH 12/17] Moved GameMode into pumpkin-core --- Cargo.lock | 2 ++ pumpkin-core/Cargo.toml | 3 +++ pumpkin-core/src/gamemode.rs | 30 +++++++++++++++++++++++++ pumpkin-core/src/lib.rs | 3 +++ pumpkin/src/client/player_packet.rs | 4 ++-- pumpkin/src/commands/cmd_gamemode.rs | 2 +- pumpkin/src/config/mod.rs | 3 ++- pumpkin/src/entity/player.rs | 33 +++------------------------- pumpkin/src/server.rs | 3 ++- 9 files changed, 48 insertions(+), 35 deletions(-) create mode 100644 pumpkin-core/src/gamemode.rs diff --git a/Cargo.lock b/Cargo.lock index 990b46cf0..e2e6ed06c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1936,6 +1936,8 @@ dependencies = [ "colored", "fastnbt", "md5", + "num-derive", + "num-traits", "serde", "uuid", ] diff --git a/pumpkin-core/Cargo.toml b/pumpkin-core/Cargo.toml index 6bd39248b..8d7ae3900 100644 --- a/pumpkin-core/Cargo.toml +++ b/pumpkin-core/Cargo.toml @@ -9,3 +9,6 @@ fastnbt = { git = "https://github.com/owengage/fastnbt.git" } uuid.workspace = true colored = "2" md5 = "0.7.0" + +num-traits = "0.2.19" +num-derive = { version = "0.4.2" } diff --git a/pumpkin-core/src/gamemode.rs b/pumpkin-core/src/gamemode.rs new file mode 100644 index 000000000..6e996a6f9 --- /dev/null +++ b/pumpkin-core/src/gamemode.rs @@ -0,0 +1,30 @@ +use std::str::FromStr; + +use num_derive::{FromPrimitive, ToPrimitive}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, PartialEq, Eq)] +pub struct ParseGameModeError; + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, FromPrimitive, ToPrimitive)] +pub enum GameMode { + Undefined = -1, + Survival, + Creative, + Adventure, + Spectator, +} + +impl FromStr for GameMode { + type Err = ParseGameModeError; + + fn from_str(s: &str) -> Result { + match s { + "survival" => Ok(Self::Survival), + "creative" => Ok(Self::Creative), + "adventure" => Ok(Self::Adventure), + "spectator" => Ok(Self::Spectator), + _ => Err(ParseGameModeError), + } + } +} diff --git a/pumpkin-core/src/lib.rs b/pumpkin-core/src/lib.rs index 4cfe1770b..d7f4f5837 100644 --- a/pumpkin-core/src/lib.rs +++ b/pumpkin-core/src/lib.rs @@ -1,2 +1,5 @@ +pub mod gamemode; pub mod random; pub mod text; + +pub use gamemode::GameMode; diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 15fe31477..4323d0eda 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -3,12 +3,12 @@ use std::f32::consts::PI; use crate::{ commands::{handle_command, CommandSender}, config::ADVANCED_CONFIG, - entity::player::{ChatMode, GameMode, Hand, Player}, + entity::player::{ChatMode, Hand, Player}, server::Server, util::math::wrap_degrees, }; use num_traits::FromPrimitive; -use pumpkin_core::text::TextComponent; +use pumpkin_core::{text::TextComponent, GameMode}; use pumpkin_entity::EntityId; use pumpkin_inventory::WindowType; use pumpkin_protocol::server::play::{SCloseContainer, SSetPlayerGround, SUseItem}; diff --git a/pumpkin/src/commands/cmd_gamemode.rs b/pumpkin/src/commands/cmd_gamemode.rs index 375172f27..17e47fea4 100644 --- a/pumpkin/src/commands/cmd_gamemode.rs +++ b/pumpkin/src/commands/cmd_gamemode.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use num_traits::FromPrimitive; use pumpkin_core::text::TextComponent; +use pumpkin_core::GameMode; use crate::commands::arg_player::{consume_arg_player, parse_arg_player}; @@ -13,7 +14,6 @@ use crate::commands::tree::{CommandTree, ConsumedArgs, RawArgs}; use crate::commands::tree_builder::{argument, require}; use crate::commands::CommandSender; use crate::commands::CommandSender::Player; -use crate::entity::player::GameMode; const NAMES: [&str; 1] = ["gamemode"]; diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index 5c854116d..6f2cb88d5 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -1,4 +1,5 @@ use log::warn; +use pumpkin_core::GameMode; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{ @@ -8,7 +9,7 @@ use std::{ sync::LazyLock, }; -use crate::{entity::player::GameMode, server::Difficulty}; +use crate::server::Difficulty; pub mod auth; pub mod proxy; diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 2ee561f41..1dd05cb50 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -1,8 +1,8 @@ -use std::{str::FromStr, sync::Arc}; +use std::sync::Arc; -use num_derive::{FromPrimitive, ToPrimitive}; +use num_derive::FromPrimitive; use num_traits::ToPrimitive; -use pumpkin_core::text::TextComponent; +use pumpkin_core::{text::TextComponent, GameMode}; use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, Entity, EntityId}; use pumpkin_inventory::player::PlayerInventory; use pumpkin_protocol::{ @@ -21,7 +21,6 @@ use pumpkin_protocol::{ ConnectionState, RawPacket, ServerPacket, VarInt, }; use pumpkin_world::vector3::Vector3; -use serde::{Deserialize, Serialize}; use crate::{ client::{authentication::GameProfile, Client}, @@ -454,29 +453,3 @@ pub enum ChatMode { CommandsOnly, Hidden, } - -#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, FromPrimitive, ToPrimitive)] -pub enum GameMode { - Undefined = -1, - Survival, - Creative, - Adventure, - Spectator, -} - -#[derive(Debug, PartialEq, Eq)] -pub struct ParseGameModeError; - -impl FromStr for GameMode { - type Err = ParseGameModeError; - - fn from_str(s: &str) -> Result { - match s { - "survival" => Ok(Self::Survival), - "creative" => Ok(Self::Creative), - "adventure" => Ok(Self::Adventure), - "spectator" => Ok(Self::Spectator), - _ => Err(ParseGameModeError), - } - } -} diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 8a2bb136a..00da103c9 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -11,6 +11,7 @@ use std::{ use base64::{engine::general_purpose, Engine}; use image::GenericImageView; use mio::Token; +use pumpkin_core::GameMode; use pumpkin_entity::EntityId; use pumpkin_plugin::PluginLoader; use pumpkin_protocol::{ @@ -26,7 +27,7 @@ use serde::{Deserialize, Serialize}; use crate::{ client::Client, config::{BasicConfiguration, BASIC_CONFIG}, - entity::player::{GameMode, Player}, + entity::player::Player, world::World, }; From a17ed23b00d6c899b124bb61ec7cd6779fbb1e02 Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Sat, 31 Aug 2024 18:18:32 +0200 Subject: [PATCH 13/17] Moved Difficulty into pumpkin-core --- pumpkin-core/src/lib.rs | 10 ++++++++++ pumpkin/src/config/mod.rs | 4 +--- pumpkin/src/server.rs | 9 --------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/pumpkin-core/src/lib.rs b/pumpkin-core/src/lib.rs index d7f4f5837..ac5bdb4a5 100644 --- a/pumpkin-core/src/lib.rs +++ b/pumpkin-core/src/lib.rs @@ -3,3 +3,13 @@ pub mod random; pub mod text; pub use gamemode::GameMode; + +use serde::{Deserialize, Serialize}; + +#[derive(PartialEq, Serialize, Deserialize)] +pub enum Difficulty { + Peaceful, + Easy, + Normal, + Hard, +} diff --git a/pumpkin/src/config/mod.rs b/pumpkin/src/config/mod.rs index 6f2cb88d5..f24ca2810 100644 --- a/pumpkin/src/config/mod.rs +++ b/pumpkin/src/config/mod.rs @@ -1,5 +1,5 @@ use log::warn; -use pumpkin_core::GameMode; +use pumpkin_core::{Difficulty, GameMode}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{ @@ -9,8 +9,6 @@ use std::{ sync::LazyLock, }; -use crate::server::Difficulty; - pub mod auth; pub mod proxy; pub mod resource_pack; diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index 00da103c9..e37f4ea0e 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -22,7 +22,6 @@ use pumpkin_world::dimension::Dimension; use pumpkin_registry::Registry; use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; -use serde::{Deserialize, Serialize}; use crate::{ client::Client, @@ -214,11 +213,3 @@ impl Server { (pub_key, priv_key) } } - -#[derive(PartialEq, Serialize, Deserialize)] -pub enum Difficulty { - Peaceful, - Easy, - Normal, - Hard, -} From 070a50833bef0d668a014d926bed70665bb0e696 Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Sat, 31 Aug 2024 18:32:48 +0200 Subject: [PATCH 14/17] Moved config into its own crate --- Cargo.lock | 11 +++++++++++ Cargo.toml | 2 +- pumpkin-config/Cargo.toml | 12 ++++++++++++ .../src/config => pumpkin-config/src}/auth.rs | 3 +-- .../config => pumpkin-config/src}/commands.rs | 0 .../src}/compression.rs | 0 .../config/mod.rs => pumpkin-config/src/lib.rs | 0 .../src/config => pumpkin-config/src}/proxy.rs | 0 .../src/config => pumpkin-config/src}/pvp.rs | 0 .../src/config => pumpkin-config/src}/rcon.rs | 0 .../src}/resource_pack.rs | 0 pumpkin-core/src/lib.rs | 7 +++++++ pumpkin/Cargo.toml | 1 + pumpkin/src/client/authentication.rs | 17 ++++------------- pumpkin/src/client/client_packet.rs | 2 +- pumpkin/src/client/player_packet.rs | 2 +- pumpkin/src/main.rs | 3 +-- pumpkin/src/proxy/velocity.rs | 3 ++- pumpkin/src/rcon/mod.rs | 3 ++- pumpkin/src/server.rs | 8 ++------ pumpkin/src/world/mod.rs | 3 ++- 21 files changed, 48 insertions(+), 29 deletions(-) create mode 100644 pumpkin-config/Cargo.toml rename {pumpkin/src/config => pumpkin-config/src}/auth.rs (97%) rename {pumpkin/src/config => pumpkin-config/src}/commands.rs (100%) rename {pumpkin/src/config => pumpkin-config/src}/compression.rs (100%) rename pumpkin/src/config/mod.rs => pumpkin-config/src/lib.rs (100%) rename {pumpkin/src/config => pumpkin-config/src}/proxy.rs (100%) rename {pumpkin/src/config => pumpkin-config/src}/pvp.rs (100%) rename {pumpkin/src/config => pumpkin-config/src}/rcon.rs (100%) rename {pumpkin/src/config => pumpkin-config/src}/resource_pack.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e2e6ed06c..b204a8850 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1906,6 +1906,7 @@ dependencies = [ "num-bigint", "num-derive", "num-traits", + "pumpkin-config", "pumpkin-core", "pumpkin-entity", "pumpkin-inventory", @@ -1929,6 +1930,16 @@ dependencies = [ "uuid", ] +[[package]] +name = "pumpkin-config" +version = "0.1.0" +dependencies = [ + "log", + "pumpkin-core", + "serde", + "toml 0.8.19", +] + [[package]] name = "pumpkin-core" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 3fbea597f..abca231fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = [ "pumpkin-core", "pumpkin-entity", "pumpkin-inventory", "pumpkin-macros/", "pumpkin-plugin", "pumpkin-protocol/", "pumpkin-registry/", "pumpkin-world", "pumpkin/"] +members = [ "pumpkin-config", "pumpkin-core", "pumpkin-entity", "pumpkin-inventory", "pumpkin-macros/", "pumpkin-plugin", "pumpkin-protocol/", "pumpkin-registry/", "pumpkin-world", "pumpkin/"] [workspace.package] version = "0.1.0" diff --git a/pumpkin-config/Cargo.toml b/pumpkin-config/Cargo.toml new file mode 100644 index 000000000..782294c9c --- /dev/null +++ b/pumpkin-config/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "pumpkin-config" +version.workspace = true +edition.workspace = true + +[dependencies] +pumpkin-core = { path = "../pumpkin-core" } + +serde = "1.0" +toml = "0.8" + +log.workspace = true diff --git a/pumpkin/src/config/auth.rs b/pumpkin-config/src/auth.rs similarity index 97% rename from pumpkin/src/config/auth.rs rename to pumpkin-config/src/auth.rs index 09c4188ff..c6606cd86 100644 --- a/pumpkin/src/config/auth.rs +++ b/pumpkin-config/src/auth.rs @@ -1,7 +1,6 @@ +use pumpkin_core::ProfileAction; use serde::{Deserialize, Serialize}; -use crate::client::authentication::ProfileAction; - #[derive(Deserialize, Serialize)] pub struct AuthenticationConfig { /// Whether to use Mojang authentication. diff --git a/pumpkin/src/config/commands.rs b/pumpkin-config/src/commands.rs similarity index 100% rename from pumpkin/src/config/commands.rs rename to pumpkin-config/src/commands.rs diff --git a/pumpkin/src/config/compression.rs b/pumpkin-config/src/compression.rs similarity index 100% rename from pumpkin/src/config/compression.rs rename to pumpkin-config/src/compression.rs diff --git a/pumpkin/src/config/mod.rs b/pumpkin-config/src/lib.rs similarity index 100% rename from pumpkin/src/config/mod.rs rename to pumpkin-config/src/lib.rs diff --git a/pumpkin/src/config/proxy.rs b/pumpkin-config/src/proxy.rs similarity index 100% rename from pumpkin/src/config/proxy.rs rename to pumpkin-config/src/proxy.rs diff --git a/pumpkin/src/config/pvp.rs b/pumpkin-config/src/pvp.rs similarity index 100% rename from pumpkin/src/config/pvp.rs rename to pumpkin-config/src/pvp.rs diff --git a/pumpkin/src/config/rcon.rs b/pumpkin-config/src/rcon.rs similarity index 100% rename from pumpkin/src/config/rcon.rs rename to pumpkin-config/src/rcon.rs diff --git a/pumpkin/src/config/resource_pack.rs b/pumpkin-config/src/resource_pack.rs similarity index 100% rename from pumpkin/src/config/resource_pack.rs rename to pumpkin-config/src/resource_pack.rs diff --git a/pumpkin-core/src/lib.rs b/pumpkin-core/src/lib.rs index ac5bdb4a5..9539acae3 100644 --- a/pumpkin-core/src/lib.rs +++ b/pumpkin-core/src/lib.rs @@ -13,3 +13,10 @@ pub enum Difficulty { Normal, Hard, } + +#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum ProfileAction { + ForcedNameChange, + UsingBannedSkin, +} diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 0494fc462..804506fd3 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -10,6 +10,7 @@ default = [] [dependencies] # pumpkin pumpkin-core = { path = "../pumpkin-core"} +pumpkin-config = { path = "../pumpkin-config" } pumpkin-plugin = { path = "../pumpkin-plugin"} pumpkin-inventory = { path = "../pumpkin-inventory"} pumpkin-world = { path = "../pumpkin-world"} diff --git a/pumpkin/src/client/authentication.rs b/pumpkin/src/client/authentication.rs index 13dc427fa..692cf266c 100644 --- a/pumpkin/src/client/authentication.rs +++ b/pumpkin/src/client/authentication.rs @@ -2,16 +2,15 @@ use std::{collections::HashMap, net::IpAddr}; use base64::{engine::general_purpose, Engine}; use num_bigint::BigInt; +use pumpkin_config::{auth::TextureConfig, ADVANCED_CONFIG}; +use pumpkin_core::ProfileAction; use pumpkin_protocol::Property; use reqwest::{StatusCode, Url}; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use thiserror::Error; use uuid::Uuid; -use crate::{ - config::{auth::TextureConfig, ADVANCED_CONFIG}, - server::Server, -}; +use crate::server::Server; #[derive(Deserialize, Clone, Debug)] #[allow(non_snake_case)] @@ -32,14 +31,6 @@ pub struct Texture { metadata: Option>, } -#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)] -pub enum ProfileAction { - #[serde(rename = "FORCED_NAME_CHANGE")] - ForcedNameChange, - #[serde(rename = "USING_BANNED_SKIN")] - UsingBannedSkin, -} - #[derive(Deserialize, Clone, Debug)] pub struct GameProfile { pub id: Uuid, diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index 855c12d57..1c70b0e7c 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -1,4 +1,5 @@ use num_traits::FromPrimitive; +use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_core::text::TextComponent; use pumpkin_protocol::{ client::{ @@ -19,7 +20,6 @@ use sha1::{Digest, Sha1}; use crate::{ client::authentication::{self, GameProfile}, - config::{ADVANCED_CONFIG, BASIC_CONFIG}, entity::player::{ChatMode, Hand}, proxy::velocity::velocity_login, server::{Server, CURRENT_MC_VERSION}, diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 4323d0eda..1602a5d89 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -2,12 +2,12 @@ use std::f32::consts::PI; use crate::{ commands::{handle_command, CommandSender}, - config::ADVANCED_CONFIG, entity::player::{ChatMode, Hand, Player}, server::Server, util::math::wrap_degrees, }; use num_traits::FromPrimitive; +use pumpkin_config::ADVANCED_CONFIG; use pumpkin_core::{text::TextComponent, GameMode}; use pumpkin_entity::EntityId; use pumpkin_inventory::WindowType; diff --git a/pumpkin/src/main.rs b/pumpkin/src/main.rs index 4acac485b..79cd54053 100644 --- a/pumpkin/src/main.rs +++ b/pumpkin/src/main.rs @@ -18,7 +18,6 @@ use server::Server; pub mod client; pub mod commands; -pub mod config; pub mod entity; pub mod proxy; pub mod rcon; @@ -29,8 +28,8 @@ pub mod world; fn main() -> io::Result<()> { use std::sync::{Arc, Mutex}; - use config::{ADVANCED_CONFIG, BASIC_CONFIG}; use entity::player::Player; + use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG}; use pumpkin_core::text::{color::NamedColor, TextComponent}; use rcon::RCONServer; diff --git a/pumpkin/src/proxy/velocity.rs b/pumpkin/src/proxy/velocity.rs index 3b06ff97a..b2f753506 100644 --- a/pumpkin/src/proxy/velocity.rs +++ b/pumpkin/src/proxy/velocity.rs @@ -2,12 +2,13 @@ use std::net::SocketAddr; use bytes::{BufMut, BytesMut}; use hmac::{Hmac, Mac}; +use pumpkin_config::proxy::VelocityConfig; use pumpkin_protocol::{ bytebuf::ByteBuffer, client::login::CLoginPluginRequest, server::login::SLoginPluginResponse, }; use sha2::Sha256; -use crate::{client::Client, config::proxy::VelocityConfig}; +use crate::client::Client; type HmacSha256 = Hmac; diff --git a/pumpkin/src/rcon/mod.rs b/pumpkin/src/rcon/mod.rs index 3f20ffd54..19a5b17d6 100644 --- a/pumpkin/src/rcon/mod.rs +++ b/pumpkin/src/rcon/mod.rs @@ -9,9 +9,10 @@ use mio::{ Events, Interest, Poll, Token, }; use packet::{Packet, PacketError, PacketType}; +use pumpkin_config::RCONConfig; use thiserror::Error; -use crate::{commands::handle_command, config::RCONConfig, server::Server}; +use crate::{commands::handle_command, server::Server}; mod packet; diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index e37f4ea0e..8082b1daf 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -11,6 +11,7 @@ use std::{ use base64::{engine::general_purpose, Engine}; use image::GenericImageView; use mio::Token; +use pumpkin_config::{BasicConfiguration, BASIC_CONFIG}; use pumpkin_core::GameMode; use pumpkin_entity::EntityId; use pumpkin_plugin::PluginLoader; @@ -23,12 +24,7 @@ use pumpkin_world::dimension::Dimension; use pumpkin_registry::Registry; use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey}; -use crate::{ - client::Client, - config::{BasicConfiguration, BASIC_CONFIG}, - entity::player::Player, - world::World, -}; +use crate::{client::Client, entity::player::Player, world::World}; pub const CURRENT_MC_VERSION: &str = "1.21.1"; diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 337f6332b..77123a0ab 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -6,6 +6,7 @@ use std::{ use mio::Token; use num_traits::ToPrimitive; +use pumpkin_config::BasicConfiguration; use pumpkin_entity::{entity_type::EntityType, EntityId}; use pumpkin_protocol::{ client::play::{ @@ -19,7 +20,7 @@ use pumpkin_protocol::{ use pumpkin_world::{level::Level, radial_chunk_iterator::RadialIterator}; use tokio::sync::mpsc; -use crate::{config::BasicConfiguration, entity::player::Player}; +use crate::entity::player::Player; pub struct World { pub level: Arc>, From 8a2e7cada879e49a9112f207632a7e2ef3fdb522 Mon Sep 17 00:00:00 2001 From: DaniD3v Date: Sat, 31 Aug 2024 20:31:13 +0200 Subject: [PATCH 15/17] Removed lazy_static!{} in favor of LazyLock --- Cargo.lock | 1 - pumpkin-world/Cargo.toml | 1 - pumpkin-world/src/block/block_registry.rs | 12 +++++------- pumpkin-world/src/global_registry.rs | 11 ++++------- pumpkin-world/src/item/item_registry.rs | 16 ++++++---------- 5 files changed, 15 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 990b46cf0..df25fdd26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2018,7 +2018,6 @@ dependencies = [ "flate2", "futures", "itertools 0.13.0", - "lazy_static", "log", "num-derive", "num-traits", diff --git a/pumpkin-world/Cargo.toml b/pumpkin-world/Cargo.toml index 4008eaa84..7a5d04191 100644 --- a/pumpkin-world/Cargo.toml +++ b/pumpkin-world/Cargo.toml @@ -15,7 +15,6 @@ thiserror = "1.0.63" futures = "0.3.30" flate2 = "1.0.33" serde = { version = "1.0", features = ["derive"] } -lazy_static = "1.5.0" serde_json = "1.0" static_assertions = "1.1.0" log.workspace = true diff --git a/pumpkin-world/src/block/block_registry.rs b/pumpkin-world/src/block/block_registry.rs index c6c9b96f4..7d7b3f69f 100644 --- a/pumpkin-world/src/block/block_registry.rs +++ b/pumpkin-world/src/block/block_registry.rs @@ -1,15 +1,13 @@ -use std::collections::HashMap; +use std::{collections::HashMap, sync::LazyLock}; -use lazy_static::lazy_static; use serde::Deserialize; use super::block_id::BlockId; -lazy_static! { - pub static ref BLOCKS: HashMap = - serde_json::from_str(include_str!("../../assets/blocks.json")) - .expect("Could not parse block.json registry."); -} +pub static BLOCKS: LazyLock> = LazyLock::new(|| { + serde_json::from_str(include_str!("../../assets/blocks.json")) + .expect("Could not parse block.json registry.") +}); #[derive(Deserialize, Debug, Clone, PartialEq, Eq)] pub struct RegistryBlockDefinition { diff --git a/pumpkin-world/src/global_registry.rs b/pumpkin-world/src/global_registry.rs index 6a7aeafa1..1723cb8f8 100644 --- a/pumpkin-world/src/global_registry.rs +++ b/pumpkin-world/src/global_registry.rs @@ -1,6 +1,4 @@ -use std::collections::HashMap; - -use lazy_static::lazy_static; +use std::{collections::HashMap, sync::LazyLock}; pub const ITEM_REGISTRY: &str = "minecraft:item"; @@ -12,10 +10,9 @@ pub struct RegistryElement { pub entries: HashMap>, } -lazy_static! { - pub static ref REGISTRY: HashMap = - serde_json::from_str(REGISTRY_JSON).expect("Could not parse registry.json registry."); -} +pub static REGISTRY: LazyLock> = LazyLock::new(|| { + serde_json::from_str(REGISTRY_JSON).expect("Could not parse registry.json registry.") +}); pub fn get_protocol_id(category: &str, entry: &str) -> u32 { *REGISTRY diff --git a/pumpkin-world/src/item/item_registry.rs b/pumpkin-world/src/item/item_registry.rs index 81794c063..9f3f64ab4 100644 --- a/pumpkin-world/src/item/item_registry.rs +++ b/pumpkin-world/src/item/item_registry.rs @@ -1,13 +1,14 @@ -use std::collections::HashMap; - -use lazy_static::lazy_static; - -use crate::global_registry::{self, ITEM_REGISTRY}; +use std::{collections::HashMap, sync::LazyLock}; use super::Rarity; +use crate::global_registry::{self, ITEM_REGISTRY}; const ITEMS_JSON: &str = include_str!("../../assets/items.json"); +pub static ITEMS: LazyLock> = LazyLock::new(|| { + serde_json::from_str(ITEMS_JSON).expect("Could not parse items.json registry.") +}); + #[derive(serde::Deserialize, Debug, Clone, PartialEq, Eq)] pub struct ItemComponents { // TODO: attribute_modifiers @@ -27,11 +28,6 @@ pub struct ItemElement { components: ItemComponents, } -lazy_static! { - pub static ref ITEMS: HashMap = - serde_json::from_str(ITEMS_JSON).expect("Could not parse items.json registry."); -} - #[allow(dead_code)] pub fn get_item_element(item_id: &str) -> &ItemComponents { &ITEMS.get(item_id).expect("Item not found").components From faceba091c562a0b104d6d99600f1ffaee7ccd3d Mon Sep 17 00:00:00 2001 From: kralverde Date: Sat, 31 Aug 2024 15:06:41 -0400 Subject: [PATCH 16/17] implement legacy_random and java string hash --- pumpkin-core/src/random/legacy_rand.rs | 326 ++++++++++++++++++++++++ pumpkin-core/src/random/mod.rs | 85 +++++- pumpkin-core/src/random/xoroshiro128.rs | 40 +-- 3 files changed, 411 insertions(+), 40 deletions(-) create mode 100644 pumpkin-core/src/random/legacy_rand.rs diff --git a/pumpkin-core/src/random/legacy_rand.rs b/pumpkin-core/src/random/legacy_rand.rs new file mode 100644 index 000000000..f7f60ff41 --- /dev/null +++ b/pumpkin-core/src/random/legacy_rand.rs @@ -0,0 +1,326 @@ +use super::{ + gaussian::GaussianGenerator, hash_block_pos, java_string_hash, Random, RandomSplitter, +}; + +struct LegacyRand { + seed: u64, + internal_next_gaussian: f64, + internal_has_next_gaussian: bool, +} + +impl LegacyRand { + fn next_random(&mut self) -> u64 { + let l = self.seed; + let m = l.wrapping_mul(0x5DEECE66D).wrapping_add(11) & 0xFFFFFFFFFFFF; + self.seed = m; + m + } +} + +impl GaussianGenerator for LegacyRand { + fn has_next_gaussian(&self) -> bool { + self.internal_has_next_gaussian + } + + fn stored_next_gaussian(&self) -> f64 { + self.internal_next_gaussian + } + + fn set_has_next_gaussian(&mut self, value: bool) { + self.internal_has_next_gaussian = value; + } + + fn set_stored_next_gaussian(&mut self, value: f64) { + self.internal_next_gaussian = value; + } +} + +impl Random for LegacyRand { + fn from_seed(seed: u64) -> Self { + LegacyRand { + seed: (seed ^ 0x5DEECE66D) & 0xFFFFFFFFFFFF, + internal_has_next_gaussian: false, + internal_next_gaussian: 0f64, + } + } + + fn next(&mut self, bits: u64) -> u64 { + self.next_random() >> (48 - bits) + } + + fn split(&mut self) -> Self { + LegacyRand::from_seed(self.next_i64() as u64) + } + + fn next_i32(&mut self) -> i32 { + self.next(32) as i32 + } + + fn next_i64(&mut self) -> i64 { + let i = self.next_i32(); + let j = self.next_i32(); + ((i as i64) << 32).wrapping_add(j as i64) + } + + fn next_f32(&mut self) -> f32 { + self.next(24) as f32 * 5.9604645E-8f32 + } + + fn next_f64(&mut self) -> f64 { + let i = self.next(26); + let j = self.next(27); + let l = (i << 27).wrapping_add(j); + l as f64 * 1.110223E-16f32 as f64 + } + + fn next_bool(&mut self) -> bool { + self.next(1) != 0 + } + + fn next_splitter(&mut self) -> impl RandomSplitter { + LegacySplitter::new(self.next_i64() as u64) + } + + fn next_gaussian(&mut self) -> f64 { + self.calculate_gaussian() + } + + fn next_bounded_i32(&mut self, bound: i32) -> i32 { + if bound & (bound - 1) == 0 { + (bound as u64).wrapping_mul(self.next(31) >> 31) as i32 + } else { + loop { + let i = self.next(31) as i32; + let j = i % bound; + if (i - j + (bound - 1)) > 0 { + return j; + } + } + } + } +} + +struct LegacySplitter { + seed: u64, +} + +impl LegacySplitter { + fn new(seed: u64) -> Self { + LegacySplitter { seed } + } +} + +impl RandomSplitter for LegacySplitter { + fn split_u64(&self, seed: u64) -> impl Random { + LegacyRand::from_seed(seed) + } + + fn split_string(&self, seed: &str) -> impl Random { + let string_hash = java_string_hash(seed); + LegacyRand::from_seed((string_hash as u64) ^ self.seed) + } + + fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random { + let pos_hash = hash_block_pos(x, y, z); + LegacyRand::from_seed((pos_hash as u64) ^ self.seed) + } +} + +#[cfg(test)] +mod test { + use crate::random::{Random, RandomSplitter}; + + use super::LegacyRand; + + #[test] + fn test_next_i32() { + let mut rand = LegacyRand::from_seed(0); + + let values = [ + -1155484576, + -723955400, + 1033096058, + -1690734402, + -1557280266, + 1327362106, + -1930858313, + 502539523, + -1728529858, + -938301587, + ]; + + for value in values { + assert_eq!(rand.next_i32(), value); + } + } + + #[test] + fn test_next_bounded_i32() { + let mut rand = LegacyRand::from_seed(0); + + let values = [0, 13, 4, 2, 5, 8, 11, 6, 9, 14]; + + for value in values { + assert_eq!(rand.next_bounded_i32(0xf), value); + } + } + + #[test] + fn test_next_inbetween_i32() { + let mut rand = LegacyRand::from_seed(0); + + let values = [1, 5, 2, 12, 12, 6, 12, 10, 4, 3]; + + for value in values { + assert_eq!(rand.next_inbetween_i32(1, 12), value); + } + } + + #[test] + fn test_next_inbetween_exclusive_i32() { + let mut rand = LegacyRand::from_seed(0); + + let values = [1, 7, 9, 6, 7, 3, 3, 7, 3, 1]; + + for value in values { + assert_eq!(rand.next_inbetween_i32_exclusive(1, 12), value); + } + } + + #[test] + fn test_next_f64() { + let mut rand = LegacyRand::from_seed(0); + + let values = [ + 0.730967787376657, + 0.24053641567148587, + 0.6374174253501083, + 0.5504370051176339, + 0.5975452777972018, + 0.3332183994766498, + 0.3851891847407185, + 0.984841540199809, + 0.8791825178724801, + 0.9412491794821144, + ]; + + for value in values { + assert_eq!(rand.next_f64(), value); + } + } + + #[test] + fn test_next_f32() { + let mut rand = LegacyRand::from_seed(0); + + let values: [f32; 10] = [ + 0.73096776, 0.831441, 0.24053639, 0.6063452, 0.6374174, 0.30905056, 0.550437, + 0.1170066, 0.59754527, 0.7815346, + ]; + + for value in values { + assert_eq!(rand.next_f32(), value); + } + } + + #[test] + fn test_next_i64() { + let mut rand = LegacyRand::from_seed(0); + + let values: [i64; 10] = [ + -4962768465676381896, + 4437113781045784766, + -6688467811848818630, + -8292973307042192125, + -7423979211207825555, + 6146794652083548235, + 7105486291024734541, + -279624296851435688, + -2228689144322150137, + -1083761183081836303, + ]; + + for value in values { + assert_eq!(rand.next_i64(), value); + } + } + + #[test] + fn test_next_bool() { + let mut rand = LegacyRand::from_seed(0); + + let values = [ + true, true, false, true, true, false, true, false, true, true, + ]; + + for value in values { + assert_eq!(rand.next_bool(), value); + } + } + + #[test] + fn test_next_gaussian() { + let mut rand = LegacyRand::from_seed(0); + + let values = [ + 0.8025330637390305, + -0.9015460884175122, + 2.080920790428163, + 0.7637707684364894, + 0.9845745328825128, + -1.6834122587673428, + -0.027290262907887285, + 0.11524570286202315, + -0.39016704137993774, + -0.643388813126449, + ]; + + for value in values { + assert_eq!(rand.next_gaussian(), value); + } + } + + #[test] + fn test_next_triangular() { + let mut rand = LegacyRand::from_seed(0); + + let values = [ + 124.52156858525856, + 104.34902101162372, + 113.2163439160276, + 70.01738222704547, + 96.89666691951828, + 107.30284075808541, + 106.16817675813144, + 79.11264482608078, + 73.96721613927062, + 81.72419521080646, + ]; + + for value in values { + assert_eq!(rand.next_triangular(100f64, 50f64), value); + } + } + + #[test] + fn test_split() { + let mut original_rand = LegacyRand::from_seed(0); + let mut new_rand = original_rand.split(); + + { + let splitter = new_rand.next_splitter(); + + let mut rand1 = splitter.split_string("TEST STRING"); + assert_eq!(rand1.next_i32(), -1170413697); + + let mut rand2 = splitter.split_u64(10); + assert_eq!(rand2.next_i32(), -1157793070); + + let mut rand3 = splitter.split_pos(1, 11, -111); + assert_eq!(rand3.next_i32(), -1213890343); + } + + assert_eq!(original_rand.next_i32(), 1033096058); + assert_eq!(new_rand.next_i32(), -888301832); + } +} diff --git a/pumpkin-core/src/random/mod.rs b/pumpkin-core/src/random/mod.rs index f56a4c182..b5389aa49 100644 --- a/pumpkin-core/src/random/mod.rs +++ b/pumpkin-core/src/random/mod.rs @@ -1,6 +1,6 @@ -pub mod xoroshiro128; - mod gaussian; +pub mod legacy_rand; +pub mod xoroshiro128; pub trait Random { fn from_seed(seed: u64) -> Self; @@ -35,7 +35,7 @@ pub trait Random { fn skip(&mut self, count: i32) { for _ in 0..count { - self.next_i32(); + self.next_i64(); } } @@ -51,3 +51,82 @@ pub trait RandomSplitter { fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random; } + +fn hash_block_pos(x: i32, y: i32, z: i32) -> i64 { + let l = (x.wrapping_mul(3129871) as i64) ^ ((z as i64).wrapping_mul(116129781i64)) ^ (y as i64); + let l = l + .wrapping_mul(l) + .wrapping_mul(42317861i64) + .wrapping_add(l.wrapping_mul(11i64)); + l >> 16 +} + +fn java_string_hash(string: &str) -> u32 { + // All byte values of latin1 align with + // the values of U+0000 - U+00FF making this code + // equivalent to both java hash implementations + + let mut result = 0u32; + + for char_encoding in string.encode_utf16() { + result = 31u32 + .wrapping_mul(result) + .wrapping_add(char_encoding as u32); + } + result +} + +#[cfg(test)] +mod tests { + + use crate::random::java_string_hash; + + use super::hash_block_pos; + + #[test] + fn block_position_hash() { + let values: [((i32, i32, i32), i64); 8] = [ + ((0, 0, 0), 0), + ((1, 1, 1), 60311958971344), + ((4, 4, 4), 120566413180880), + ((25, 25, 25), 111753446486209), + ((676, 676, 676), 75210837988243), + ((458329, 458329, 458329), -43764888250), + ((-387008604, -387008604, -387008604), 8437923733503), + ((176771161, 176771161, 176771161), 18421337580760), + ]; + + for ((x, y, z), value) in values { + assert_eq!(hash_block_pos(x, y, z), value); + } + } + + #[test] + fn test_java_string_hash() { + let values = [ + ("", 0), + ("1", 49), + ("TEST", 2571410), + ("TEST1", 79713759), + ("TEST0123456789", 506557463), + ( + " !\"#$%&'()*+,-./0123456789:\ + ;<=>?@ABCDEFGHIJKLMNOPQRST\ + UVWXYZ[\\]^_`abcdefghijklm\ + nopqrstuvwxyz{|}~¡¢£¤¥¦§¨©\ + ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄ\ + ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞ\ + ßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ", + (-1992287231i32) as u32, + ), + ("求同存异", 847053876), + // This might look wierd because hebrew is text is right to left + ("אבְּרֵאשִׁ֖ית בָּרָ֣א אֱלֹהִ֑ים אֵ֥ת הַשָּׁמַ֖יִם וְאֵ֥ת הָאָֽרֶץ:", 1372570871), + ("संस्कृत-", 1748614838), + ]; + + for (string, value) in values { + assert_eq!(java_string_hash(string), value); + } + } +} diff --git a/pumpkin-core/src/random/xoroshiro128.rs b/pumpkin-core/src/random/xoroshiro128.rs index dea1255ad..e8d7e4f12 100644 --- a/pumpkin-core/src/random/xoroshiro128.rs +++ b/pumpkin-core/src/random/xoroshiro128.rs @@ -1,4 +1,4 @@ -use super::{gaussian::GaussianGenerator, Random, RandomSplitter}; +use super::{gaussian::GaussianGenerator, hash_block_pos, Random, RandomSplitter}; pub struct Xoroshiro { lo: u64, @@ -130,12 +130,6 @@ impl Random for Xoroshiro { fn next_gaussian(&mut self) -> f64 { self.calculate_gaussian() } - - fn skip(&mut self, count: i32) { - for _ in 0..count { - self.next_random(); - } - } } pub struct XoroshiroSplitter { @@ -143,19 +137,9 @@ pub struct XoroshiroSplitter { hi: u64, } -fn hash_pos(x: i32, y: i32, z: i32) -> i64 { - let l = - ((x.wrapping_mul(3129871)) as i64) ^ ((z as i64).wrapping_mul(116129781i64)) ^ (y as i64); - let l = l - .wrapping_mul(l) - .wrapping_mul(42317861i64) - .wrapping_add(l.wrapping_mul(11i64)); - l >> 16 -} - impl RandomSplitter for XoroshiroSplitter { fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random { - let l = hash_pos(x, y, z) as u64; + let l = hash_block_pos(x, y, z) as u64; let m = l ^ self.lo; Xoroshiro::new(m, self.hi) } @@ -177,28 +161,10 @@ impl RandomSplitter for XoroshiroSplitter { mod tests { use crate::random::{Random, RandomSplitter}; - use super::{hash_pos, mix_stafford_13, Xoroshiro}; + use super::{mix_stafford_13, Xoroshiro}; // Values checked against results from the equivalent Java source - #[test] - fn block_position_hash() { - let values: [((i32, i32, i32), i64); 8] = [ - ((0, 0, 0), 0), - ((1, 1, 1), 60311958971344), - ((4, 4, 4), 120566413180880), - ((25, 25, 25), 111753446486209), - ((676, 676, 676), 75210837988243), - ((458329, 458329, 458329), -43764888250), - ((-387008604, -387008604, -387008604), 8437923733503), - ((176771161, 176771161, 176771161), 18421337580760), - ]; - - for ((x, y, z), value) in values { - assert_eq!(hash_pos(x, y, z), value); - } - } - #[test] fn test_mix_stafford_13() { let values: [(u64, i64); 31] = [ From 5c0dffbf9dd3d9b55fbc937dd5ddf392f004fe93 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Sun, 1 Sep 2024 18:04:27 +0200 Subject: [PATCH 17/17] Dynamic chunk loading --- Cargo.lock | 2 + pumpkin-core/src/lib.rs | 1 + .../src/math}/boundingbox.rs | 5 +- .../math.rs => pumpkin-core/src/math/mod.rs | 11 ++ .../src => pumpkin-core/src/math}/position.rs | 4 +- .../src => pumpkin-core/src/math}/vector2.rs | 0 .../src => pumpkin-core/src/math}/vector3.rs | 0 pumpkin-entity/Cargo.toml | 2 + pumpkin-entity/src/lib.rs | 43 +++++--- pumpkin-protocol/src/bytebuf/packet_id.rs | 22 ++-- .../src/client/play/c_block_destroy_stage.rs | 3 +- .../src/client/play/c_block_update.rs | 3 +- pumpkin-protocol/src/client/play/c_login.rs | 3 +- .../src/client/play/c_worldevent.rs | 3 +- pumpkin-protocol/src/lib.rs | 1 - .../src/server/play/s_player_action.rs | 3 +- .../src/server/play/s_use_item_on.rs | 3 +- pumpkin-world/Cargo.toml | 4 +- pumpkin-world/src/block/mod.rs | 2 +- pumpkin-world/src/chunk.rs | 2 +- pumpkin-world/src/coordinates.rs | 3 +- .../src/cylindrical_chunk_iterator.rs | 83 ++++++++++++++ pumpkin-world/src/level.rs | 2 +- pumpkin-world/src/lib.rs | 4 +- pumpkin-world/src/radial_chunk_iterator.rs | 59 ---------- pumpkin-world/src/world_gen/generator.rs | 2 +- .../src/world_gen/generic_generator.rs | 3 +- pumpkin/src/client/mod.rs | 1 + pumpkin/src/client/player_packet.rs | 66 +++++++----- pumpkin/src/entity/player.rs | 54 ++++++---- pumpkin/src/util/mod.rs | 3 +- pumpkin/src/world/mod.rs | 49 ++++----- pumpkin/src/world/player_chunker.rs | 102 ++++++++++++++++++ 33 files changed, 367 insertions(+), 181 deletions(-) rename {pumpkin/src/util => pumpkin-core/src/math}/boundingbox.rs (89%) rename pumpkin/src/util/math.rs => pumpkin-core/src/math/mod.rs (51%) rename {pumpkin-protocol/src => pumpkin-core/src/math}/position.rs (96%) rename {pumpkin-world/src => pumpkin-core/src/math}/vector2.rs (100%) rename {pumpkin-world/src => pumpkin-core/src/math}/vector3.rs (100%) create mode 100644 pumpkin-world/src/cylindrical_chunk_iterator.rs delete mode 100644 pumpkin-world/src/radial_chunk_iterator.rs create mode 100644 pumpkin/src/world/player_chunker.rs diff --git a/Cargo.lock b/Cargo.lock index 7fa6f7335..d0496d2b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1959,6 +1959,7 @@ version = "0.1.0" dependencies = [ "num-derive", "num-traits", + "pumpkin-core", ] [[package]] @@ -2034,6 +2035,7 @@ dependencies = [ "log", "num-derive", "num-traits", + "pumpkin-core", "rayon", "serde", "serde_json", diff --git a/pumpkin-core/src/lib.rs b/pumpkin-core/src/lib.rs index 9539acae3..f566404df 100644 --- a/pumpkin-core/src/lib.rs +++ b/pumpkin-core/src/lib.rs @@ -1,4 +1,5 @@ pub mod gamemode; +pub mod math; pub mod random; pub mod text; diff --git a/pumpkin/src/util/boundingbox.rs b/pumpkin-core/src/math/boundingbox.rs similarity index 89% rename from pumpkin/src/util/boundingbox.rs rename to pumpkin-core/src/math/boundingbox.rs index cc32ebbfa..800a954a5 100644 --- a/pumpkin/src/util/boundingbox.rs +++ b/pumpkin-core/src/math/boundingbox.rs @@ -1,5 +1,4 @@ -use pumpkin_protocol::position::WorldPosition; -use pumpkin_world::vector3::Vector3; +use super::{position::WorldPosition, vector3::Vector3}; pub struct BoundingBox { pub min_x: f64, @@ -38,6 +37,6 @@ impl BoundingBox { let d = f64::max(f64::max(self.min_x - pos.x, pos.x - self.max_x), 0.0); let e = f64::max(f64::max(self.min_y - pos.y, pos.y - self.max_y), 0.0); let f = f64::max(f64::max(self.min_z - pos.z, pos.z - self.max_z), 0.0); - super::math::squared_magnitude(d, e, f) + super::squared_magnitude(d, e, f) } } diff --git a/pumpkin/src/util/math.rs b/pumpkin-core/src/math/mod.rs similarity index 51% rename from pumpkin/src/util/math.rs rename to pumpkin-core/src/math/mod.rs index ec4ff43d8..14922e321 100644 --- a/pumpkin/src/util/math.rs +++ b/pumpkin-core/src/math/mod.rs @@ -1,3 +1,8 @@ +pub mod boundingbox; +pub mod position; +pub mod vector2; +pub mod vector3; + pub fn wrap_degrees(var: f32) -> f32 { let mut var1 = var % 360.0; if var1 >= 180.0 { @@ -14,3 +19,9 @@ pub fn wrap_degrees(var: f32) -> f32 { pub fn squared_magnitude(a: f64, b: f64, c: f64) -> f64 { a * a + b * b + c * c } + +/// Converts a world coordinate to the corresponding chunk-section coordinate. +// TODO: This proberbly should place not here +pub fn get_section_cord(coord: i32) -> i32 { + coord >> 4 +} diff --git a/pumpkin-protocol/src/position.rs b/pumpkin-core/src/math/position.rs similarity index 96% rename from pumpkin-protocol/src/position.rs rename to pumpkin-core/src/math/position.rs index b9eed35e4..c324e89df 100644 --- a/pumpkin-protocol/src/position.rs +++ b/pumpkin-core/src/math/position.rs @@ -1,6 +1,8 @@ -use pumpkin_world::vector3::Vector3; use serde::{Deserialize, Serialize}; +use super::vector3::Vector3; + +/// Aka Block Position pub struct WorldPosition(pub Vector3); impl Serialize for WorldPosition { diff --git a/pumpkin-world/src/vector2.rs b/pumpkin-core/src/math/vector2.rs similarity index 100% rename from pumpkin-world/src/vector2.rs rename to pumpkin-core/src/math/vector2.rs diff --git a/pumpkin-world/src/vector3.rs b/pumpkin-core/src/math/vector3.rs similarity index 100% rename from pumpkin-world/src/vector3.rs rename to pumpkin-core/src/math/vector3.rs diff --git a/pumpkin-entity/Cargo.toml b/pumpkin-entity/Cargo.toml index 6e73e97cc..2b96f7651 100644 --- a/pumpkin-entity/Cargo.toml +++ b/pumpkin-entity/Cargo.toml @@ -4,5 +4,7 @@ version.workspace = true edition.workspace = true [dependencies] +pumpkin-core = { path = "../pumpkin-core"} + num-traits = "0.2" num-derive = "0.4" \ No newline at end of file diff --git a/pumpkin-entity/src/lib.rs b/pumpkin-entity/src/lib.rs index 0e1c8338a..bf7e91c00 100644 --- a/pumpkin-entity/src/lib.rs +++ b/pumpkin-entity/src/lib.rs @@ -1,5 +1,8 @@ use entity_type::EntityType; use pose::EntityPose; +use pumpkin_core::math::{ + get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3, +}; pub mod entity_type; pub mod pose; @@ -9,12 +12,10 @@ pub type EntityId = i32; pub struct Entity { pub entity_id: EntityId, pub entity_type: EntityType, - pub x: f64, - pub y: f64, - pub z: f64, - pub lastx: f64, - pub lasty: f64, - pub lastz: f64, + pub pos: Vector3, + pub block_pos: WorldPosition, + pub chunk_pos: Vector2, + pub yaw: f32, pub head_yaw: f32, pub pitch: f32, @@ -28,12 +29,9 @@ impl Entity { Self { entity_id, entity_type, - x: 0.0, - y: 0.0, - z: 0.0, - lastx: 0.0, - lasty: 0.0, - lastz: 0.0, + pos: Vector3::new(0.0, 0.0, 0.0), + block_pos: WorldPosition(Vector3::new(0, 0, 0)), + chunk_pos: Vector2::new(0, 0), yaw: 0.0, head_yaw: 0.0, pitch: 0.0, @@ -41,4 +39,25 @@ impl Entity { pose: EntityPose::Standing, } } + + pub fn set_pos(&mut self, x: f64, y: f64, z: f64) { + if self.pos.x != x || self.pos.y != y || self.pos.z != z { + self.pos = Vector3::new(x, y, z); + let i = x.floor() as i32; + let j = y.floor() as i32; + let k = z.floor() as i32; + + let block_pos = self.block_pos.0; + if i != block_pos.x || j != block_pos.y || k != block_pos.z { + self.block_pos = WorldPosition(Vector3::new(i, j, k)); + + if get_section_cord(i) != self.chunk_pos.x + || get_section_cord(k) != self.chunk_pos.z + { + self.chunk_pos = + Vector2::new(get_section_cord(block_pos.x), get_section_cord(block_pos.z)); + } + } + } + } } diff --git a/pumpkin-protocol/src/bytebuf/packet_id.rs b/pumpkin-protocol/src/bytebuf/packet_id.rs index 635a8051e..a422e247a 100644 --- a/pumpkin-protocol/src/bytebuf/packet_id.rs +++ b/pumpkin-protocol/src/bytebuf/packet_id.rs @@ -1,3 +1,4 @@ +use bytes::BufMut; use serde::{ de::{self, DeserializeOwned, SeqAccess, Visitor}, Deserialize, Deserializer, Serialize, Serializer, @@ -22,19 +23,16 @@ impl Serialize for VarInt { where S: Serializer, { - let mut val = self.0; - let mut buf: Vec = Vec::new(); - for _ in 0..5 { - let mut b: u8 = val as u8 & 0b01111111; - val >>= 7; - if val != 0 { - b |= 0b10000000; - } - buf.push(b); - if val == 0 { - break; - } + let mut value = self.0 as u32; + let mut buf = Vec::new(); + + while value > 0x7F { + buf.put_u8(value as u8 | 0x80); + value >>= 7; } + + buf.put_u8(value as u8); + serializer.serialize_bytes(&buf) } } diff --git a/pumpkin-protocol/src/client/play/c_block_destroy_stage.rs b/pumpkin-protocol/src/client/play/c_block_destroy_stage.rs index d671f985f..2f57eb42f 100644 --- a/pumpkin-protocol/src/client/play/c_block_destroy_stage.rs +++ b/pumpkin-protocol/src/client/play/c_block_destroy_stage.rs @@ -1,7 +1,8 @@ +use pumpkin_core::math::position::WorldPosition; use pumpkin_macros::packet; use serde::Serialize; -use crate::{position::WorldPosition, VarInt}; +use crate::VarInt; #[derive(Serialize)] #[packet(0x06)] diff --git a/pumpkin-protocol/src/client/play/c_block_update.rs b/pumpkin-protocol/src/client/play/c_block_update.rs index d2cd09dd2..8c73b9144 100644 --- a/pumpkin-protocol/src/client/play/c_block_update.rs +++ b/pumpkin-protocol/src/client/play/c_block_update.rs @@ -1,7 +1,8 @@ +use pumpkin_core::math::position::WorldPosition; use pumpkin_macros::packet; use serde::Serialize; -use crate::{position::WorldPosition, VarInt}; +use crate::VarInt; #[derive(Serialize)] #[packet(0x09)] diff --git a/pumpkin-protocol/src/client/play/c_login.rs b/pumpkin-protocol/src/client/play/c_login.rs index 0e0b12224..7990bba96 100644 --- a/pumpkin-protocol/src/client/play/c_login.rs +++ b/pumpkin-protocol/src/client/play/c_login.rs @@ -1,7 +1,8 @@ +use pumpkin_core::math::position::WorldPosition; use pumpkin_macros::packet; use serde::Serialize; -use crate::{position::WorldPosition, VarInt}; +use crate::VarInt; #[derive(Serialize)] #[packet(0x2B)] diff --git a/pumpkin-protocol/src/client/play/c_worldevent.rs b/pumpkin-protocol/src/client/play/c_worldevent.rs index c9447b71c..a7d479684 100644 --- a/pumpkin-protocol/src/client/play/c_worldevent.rs +++ b/pumpkin-protocol/src/client/play/c_worldevent.rs @@ -1,8 +1,7 @@ +use pumpkin_core::math::position::WorldPosition; use pumpkin_macros::packet; use serde::Serialize; -use crate::position::WorldPosition; - #[derive(Serialize)] #[packet(0x28)] pub struct CWorldEvent<'a> { diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index e79388163..dcc139b78 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -8,7 +8,6 @@ pub mod bytebuf; pub mod client; pub mod packet_decoder; pub mod packet_encoder; -pub mod position; pub mod server; pub mod slot; pub mod uuid; diff --git a/pumpkin-protocol/src/server/play/s_player_action.rs b/pumpkin-protocol/src/server/play/s_player_action.rs index 3753ee22a..92f9dcace 100644 --- a/pumpkin-protocol/src/server/play/s_player_action.rs +++ b/pumpkin-protocol/src/server/play/s_player_action.rs @@ -1,7 +1,8 @@ use num_derive::FromPrimitive; +use pumpkin_core::math::position::WorldPosition; use pumpkin_macros::packet; -use crate::{position::WorldPosition, VarInt}; +use crate::VarInt; #[derive(serde::Deserialize)] #[packet(0x24)] diff --git a/pumpkin-protocol/src/server/play/s_use_item_on.rs b/pumpkin-protocol/src/server/play/s_use_item_on.rs index b25b761db..fd3c1a02e 100644 --- a/pumpkin-protocol/src/server/play/s_use_item_on.rs +++ b/pumpkin-protocol/src/server/play/s_use_item_on.rs @@ -1,7 +1,8 @@ +use pumpkin_core::math::position::WorldPosition; use pumpkin_macros::packet; use serde::Deserialize; -use crate::{position::WorldPosition, VarInt}; +use crate::VarInt; #[derive(Deserialize)] #[packet(0x38)] diff --git a/pumpkin-world/Cargo.toml b/pumpkin-world/Cargo.toml index 7a5d04191..2bc06f7f1 100644 --- a/pumpkin-world/Cargo.toml +++ b/pumpkin-world/Cargo.toml @@ -4,7 +4,9 @@ version.workspace = true edition.workspace = true [dependencies] -# fastanvil = "0.31" +pumpkin-core = { path = "../pumpkin-core"} + + fastnbt = { git = "https://github.com/owengage/fastnbt.git" } fastsnbt = "0.2" tokio.workspace = true diff --git a/pumpkin-world/src/block/mod.rs b/pumpkin-world/src/block/mod.rs index 59dc8a083..f5fbab664 100644 --- a/pumpkin-world/src/block/mod.rs +++ b/pumpkin-world/src/block/mod.rs @@ -1,10 +1,10 @@ -use crate::vector3::Vector3; use num_derive::FromPrimitive; pub mod block_id; mod block_registry; pub use block_id::BlockId; +use pumpkin_core::math::vector3::Vector3; #[derive(FromPrimitive)] pub enum BlockFace { diff --git a/pumpkin-world/src/chunk.rs b/pumpkin-world/src/chunk.rs index 0ceddf82e..1c13d423c 100644 --- a/pumpkin-world/src/chunk.rs +++ b/pumpkin-world/src/chunk.rs @@ -3,13 +3,13 @@ use std::collections::HashMap; use std::ops::Index; use fastnbt::LongArray; +use pumpkin_core::math::vector2::Vector2; use serde::{Deserialize, Serialize}; use crate::{ block::BlockId, coordinates::{ChunkRelativeBlockCoordinates, Height}, level::{ChunkNotGeneratedError, WorldError}, - vector2::Vector2, WORLD_HEIGHT, }; diff --git a/pumpkin-world/src/coordinates.rs b/pumpkin-world/src/coordinates.rs index b474a1369..fed4a49c4 100644 --- a/pumpkin-world/src/coordinates.rs +++ b/pumpkin-world/src/coordinates.rs @@ -2,9 +2,10 @@ use std::ops::Deref; use derive_more::derive::{AsMut, AsRef, Display, Into}; use num_traits::{PrimInt, Signed, Unsigned}; +use pumpkin_core::math::vector2::Vector2; use serde::{Deserialize, Serialize}; -use crate::{vector2::Vector2, WORLD_LOWEST_Y, WORLD_MAX_Y}; +use crate::{WORLD_LOWEST_Y, WORLD_MAX_Y}; #[derive( Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, AsRef, AsMut, Into, Display, diff --git a/pumpkin-world/src/cylindrical_chunk_iterator.rs b/pumpkin-world/src/cylindrical_chunk_iterator.rs new file mode 100644 index 000000000..24c49c9da --- /dev/null +++ b/pumpkin-world/src/cylindrical_chunk_iterator.rs @@ -0,0 +1,83 @@ +use pumpkin_core::math::vector2::Vector2; + +#[derive(Debug, PartialEq)] +pub struct Cylindrical { + pub center: Vector2, + pub view_distance: i32, +} + +impl Cylindrical { + pub fn new(center: Vector2, view_distance: i32) -> Self { + Self { + center, + view_distance, + } + } + + #[allow(unused_variables)] + pub fn for_each_changed_chunk( + old_cylindrical: Cylindrical, + new_cylindrical: Cylindrical, + mut newly_included: impl FnMut(Vector2), + just_removed: impl FnMut(Vector2), + ignore: bool, + ) { + let min_x = old_cylindrical.get_left().min(new_cylindrical.get_left()); + let max_x = old_cylindrical.get_right().max(new_cylindrical.get_right()); + let min_z = old_cylindrical + .get_bottom() + .min(new_cylindrical.get_bottom()); + let max_z = old_cylindrical.get_top().max(new_cylindrical.get_top()); + + for x in min_x..=max_x { + for z in min_z..=max_z { + // TODO + // let old_is_within = if ignore { + // false + // } else { + // old_cylindrical.is_within_distance(x, z) + // }; + // let new_is_within = if ignore { + // true + // } else { + // new_cylindrical.is_within_distance(x, z) + // }; + + // if old_is_within != new_is_within { + // if new_is_within { + newly_included(Vector2::new(x, z)); + // } else { + // dbg!("aa"); + // just_removed(Vector2::new(x, z)); + // } + // } + } + } + } + + fn get_left(&self) -> i32 { + self.center.x - self.view_distance - 1 + } + + fn get_bottom(&self) -> i32 { + self.center.z - self.view_distance - 1 + } + + fn get_right(&self) -> i32 { + self.center.x + self.view_distance + 1 + } + + fn get_top(&self) -> i32 { + self.center.z + self.view_distance + 1 + } + + #[allow(dead_code)] + fn is_within_distance(&self, x: i32, z: i32) -> bool { + let max_dist_squared = self.view_distance * self.view_distance; + let max_dist = self.view_distance as i64; + let dist_x = (x - self.center.x).abs().max(0) - (1); + let dist_z = (z - self.center.z).abs().max(0) - (1); + let dist_squared = dist_x.pow(2) + (max_dist.min(dist_z as i64) as i32).pow(2); + dist_squared < max_dist_squared + } +} diff --git a/pumpkin-world/src/level.rs b/pumpkin-world/src/level.rs index 5cece51ab..3b63b58c4 100644 --- a/pumpkin-world/src/level.rs +++ b/pumpkin-world/src/level.rs @@ -8,13 +8,13 @@ use std::{ use flate2::{bufread::ZlibDecoder, read::GzDecoder}; use itertools::Itertools; +use pumpkin_core::math::vector2::Vector2; use rayon::prelude::*; use thiserror::Error; use tokio::sync::mpsc; use crate::{ chunk::ChunkData, - vector2::Vector2, world_gen::{get_world_gen, Seed, WorldGenerator}, }; diff --git a/pumpkin-world/src/lib.rs b/pumpkin-world/src/lib.rs index d39541411..dc1e73d1a 100644 --- a/pumpkin-world/src/lib.rs +++ b/pumpkin-world/src/lib.rs @@ -2,13 +2,11 @@ pub mod biome; pub mod block; pub mod chunk; pub mod coordinates; +pub mod cylindrical_chunk_iterator; pub mod dimension; pub mod global_registry; pub mod item; pub mod level; -pub mod radial_chunk_iterator; -pub mod vector2; -pub mod vector3; mod world_gen; pub const WORLD_HEIGHT: usize = 384; diff --git a/pumpkin-world/src/radial_chunk_iterator.rs b/pumpkin-world/src/radial_chunk_iterator.rs deleted file mode 100644 index f75acb7df..000000000 --- a/pumpkin-world/src/radial_chunk_iterator.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::vector2::Vector2; - -pub struct RadialIterator { - radius: u32, - direction: usize, - current: Vector2, - step_size: i32, - steps_taken: u32, - steps_in_direction: i32, -} - -impl RadialIterator { - pub fn new(radius: u32) -> Self { - RadialIterator { - radius, - direction: 0, - current: Vector2::new(0, 0), - step_size: 1, - steps_taken: 0, - steps_in_direction: 0, - } - } -} - -impl Iterator for RadialIterator { - type Item = Vector2; - - fn next(&mut self) -> Option { - if self.steps_taken >= self.radius * self.radius * 4 { - return None; - } - - let result = self.current; - - self.steps_in_direction += 1; - - // Move in the current direction - match self.direction { - 0 => self.current.x += 1, // East - 1 => self.current.z += 1, // North - 2 => self.current.x -= 1, // West - 3 => self.current.z -= 1, // South - _ => {} - } - - if self.steps_in_direction >= self.step_size { - self.direction = (self.direction + 1) % 4; - self.steps_in_direction = 0; - - // Increase step size after completing two directions - if self.direction == 0 || self.direction == 2 { - self.step_size += 1; - } - } - - self.steps_taken += 1; - Some(result) - } -} diff --git a/pumpkin-world/src/world_gen/generator.rs b/pumpkin-world/src/world_gen/generator.rs index 14e2a5aa2..75ec90838 100644 --- a/pumpkin-world/src/world_gen/generator.rs +++ b/pumpkin-world/src/world_gen/generator.rs @@ -1,10 +1,10 @@ +use pumpkin_core::math::vector2::Vector2; use static_assertions::assert_obj_safe; use crate::biome::Biome; use crate::block::BlockId; use crate::chunk::ChunkData; use crate::coordinates::{BlockCoordinates, XZBlockCoordinates}; -use crate::vector2::Vector2; use crate::world_gen::Seed; pub trait GeneratorInit { diff --git a/pumpkin-world/src/world_gen/generic_generator.rs b/pumpkin-world/src/world_gen/generic_generator.rs index 0f71589c6..6cb87ce22 100644 --- a/pumpkin-world/src/world_gen/generic_generator.rs +++ b/pumpkin-world/src/world_gen/generic_generator.rs @@ -1,7 +1,8 @@ +use pumpkin_core::math::vector2::Vector2; + use crate::{ chunk::{ChunkBlocks, ChunkData}, coordinates::{ChunkRelativeBlockCoordinates, ChunkRelativeXZBlockCoordinates}, - vector2::Vector2, WORLD_LOWEST_Y, WORLD_MAX_Y, }; diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 913019b90..131e12df9 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -34,6 +34,7 @@ mod client_packet; mod container; pub mod player_packet; +#[derive(Clone)] pub struct PlayerConfig { pub locale: String, // 16 pub view_distance: i8, diff --git a/pumpkin/src/client/player_packet.rs b/pumpkin/src/client/player_packet.rs index 1602a5d89..45fb667a5 100644 --- a/pumpkin/src/client/player_packet.rs +++ b/pumpkin/src/client/player_packet.rs @@ -4,11 +4,15 @@ use crate::{ commands::{handle_command, CommandSender}, entity::player::{ChatMode, Hand, Player}, server::Server, - util::math::wrap_degrees, + world::player_chunker, }; use num_traits::FromPrimitive; use pumpkin_config::ADVANCED_CONFIG; -use pumpkin_core::{text::TextComponent, GameMode}; +use pumpkin_core::{ + math::{position::WorldPosition, wrap_degrees}, + text::TextComponent, + GameMode, +}; use pumpkin_entity::EntityId; use pumpkin_inventory::WindowType; use pumpkin_protocol::server::play::{SCloseContainer, SSetPlayerGround, SUseItem}; @@ -18,7 +22,6 @@ use pumpkin_protocol::{ CHeadRot, CHurtAnimation, CPingResponse, CPlayerChatMessage, CUpdateEntityPos, CUpdateEntityPosRot, CUpdateEntityRot, CWorldEvent, FilterType, }, - position::WorldPosition, server::play::{ Action, ActionType, SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract, SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition, @@ -46,9 +49,7 @@ impl Player { if let Some((id, position)) = self.awaiting_teleport.as_ref() { if id == &confirm_teleport.teleport_id { // we should set the pos now to that we requested in the teleport packet, Is may fixed issues when the client sended position packets while being teleported - self.entity.x = position.x; - self.entity.y = position.y; - self.entity.z = position.z; + self.entity.set_pos(position.x, position.y, position.z); self.awaiting_teleport = None; } else { @@ -75,21 +76,24 @@ impl Player { return; } let entity = &mut self.entity; - entity.lastx = entity.x; - entity.lasty = entity.y; - entity.lastz = entity.z; - entity.x = Self::clamp_horizontal(position.x); - entity.y = Self::clamp_vertical(position.feet_y); - entity.z = Self::clamp_horizontal(position.z); + self.lastx = entity.pos.x; + self.lasty = entity.pos.y; + self.lastz = entity.pos.z; + entity.set_pos( + Self::clamp_horizontal(position.x), + Self::clamp_vertical(position.feet_y), + Self::clamp_horizontal(position.z), + ); // TODO: teleport when moving > 8 block // send new position to all other players let on_ground = self.on_ground; let entity_id = entity.entity_id; - let (x, lastx) = (entity.x, entity.lastx); - let (y, lasty) = (entity.y, entity.lasty); - let (z, lastz) = (entity.z, entity.lastz); - let world = self.world.lock().await; + let (x, lastx) = (entity.pos.x, self.lastx); + let (y, lasty) = (entity.pos.y, self.lasty); + let (z, lastz) = (entity.pos.z, self.lastz); + let world = self.world.clone(); + let world = world.lock().await; world.broadcast_packet( &[&self.client.token], &CUpdateEntityPos::new( @@ -100,6 +104,7 @@ impl Player { on_ground, ), ); + player_chunker::update_position(&world, self).await; } pub async fn handle_position_rotation( @@ -120,25 +125,28 @@ impl Player { } let entity = &mut self.entity; - entity.lastx = entity.x; - entity.lasty = entity.y; - entity.lastz = entity.z; - entity.x = Self::clamp_horizontal(position_rotation.x); - entity.y = Self::clamp_vertical(position_rotation.feet_y); - entity.z = Self::clamp_horizontal(position_rotation.z); + self.lastx = entity.pos.x; + self.lasty = entity.pos.y; + self.lastz = entity.pos.z; + entity.set_pos( + Self::clamp_horizontal(position_rotation.x), + Self::clamp_vertical(position_rotation.feet_y), + Self::clamp_horizontal(position_rotation.z), + ); entity.yaw = wrap_degrees(position_rotation.yaw) % 360.0; entity.pitch = wrap_degrees(position_rotation.pitch).clamp(-90.0, 90.0) % 360.0; // send new position to all other players let on_ground = self.on_ground; let entity_id = entity.entity_id; - let (x, lastx) = (entity.x, entity.lastx); - let (y, lasty) = (entity.y, entity.lasty); - let (z, lastz) = (entity.z, entity.lastz); + let (x, lastx) = (entity.pos.x, self.lastx); + let (y, lasty) = (entity.pos.y, self.lasty); + let (z, lastz) = (entity.pos.z, self.lastz); let yaw = modulus(entity.yaw * 256.0 / 360.0, 256.0); let pitch = modulus(entity.pitch * 256.0 / 360.0, 256.0); // let head_yaw = (entity.head_yaw * 256.0 / 360.0).floor(); - let world = self.world.lock().await; + let world = self.world.clone(); + let world = world.lock().await; world.broadcast_packet( &[&self.client.token], @@ -156,6 +164,8 @@ impl Player { &[&self.client.token], &CHeadRot::new(entity_id.into(), yaw as u8), ); + + player_chunker::update_position(&world, self).await; } pub async fn handle_rotation(&mut self, _server: &mut Server, rotation: SPlayerRotation) { @@ -299,7 +309,7 @@ impl Player { Hand::from_i32(client_information.main_hand.into()), ChatMode::from_i32(client_information.chat_mode.into()), ) { - self.client.config = Some(PlayerConfig { + self.config = PlayerConfig { locale: client_information.locale, view_distance: client_information.view_distance, chat_mode, @@ -308,7 +318,7 @@ impl Player { main_hand, text_filtering: client_information.text_filtering, server_listing: client_information.server_listing, - }); + }; } else { self.kick(TextComponent::text("Invalid hand or chat type")) } diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 1dd05cb50..d5688a5d6 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -2,7 +2,11 @@ use std::sync::Arc; use num_derive::FromPrimitive; use num_traits::ToPrimitive; -use pumpkin_core::{text::TextComponent, GameMode}; +use pumpkin_core::{ + math::{boundingbox::BoundingBox, position::WorldPosition, vector3::Vector3}, + text::TextComponent, + GameMode, +}; use pumpkin_entity::{entity_type::EntityType, pose::EntityPose, Entity, EntityId}; use pumpkin_inventory::player::PlayerInventory; use pumpkin_protocol::{ @@ -11,7 +15,6 @@ use pumpkin_protocol::{ CGameEvent, CPlayDisconnect, CPlayerAbilities, CPlayerInfoUpdate, CSetEntityMetadata, CSyncPlayerPosition, CSystemChatMessage, Metadata, PlayerAction, }, - position::WorldPosition, server::play::{ SChatCommand, SChatMessage, SClientInformationPlay, SConfirmTeleport, SInteract, SPlayPingRequest, SPlayerAction, SPlayerCommand, SPlayerPosition, SPlayerPositionRotation, @@ -20,12 +23,10 @@ use pumpkin_protocol::{ }, ConnectionState, RawPacket, ServerPacket, VarInt, }; -use pumpkin_world::vector3::Vector3; use crate::{ - client::{authentication::GameProfile, Client}, + client::{authentication::GameProfile, Client, PlayerConfig}, server::Server, - util::boundingbox::BoundingBox, world::World, }; @@ -55,6 +56,7 @@ pub struct Player { pub gameprofile: GameProfile, pub client: Client, pub entity: Entity, + pub config: PlayerConfig, // TODO: Put this into entity pub world: Arc>, /// Current gamemode @@ -67,6 +69,9 @@ pub struct Player { /// send `send_abilties_update` when changed pub abilities: PlayerAbilities, + pub lastx: f64, + pub lasty: f64, + pub lastz: f64, // Client side value, Should be not trusted pub on_ground: bool, @@ -82,6 +87,8 @@ pub struct Player { pub teleport_id_count: i32, // Current awaiting teleport id and location, None if did not teleport pub awaiting_teleport: Option<(VarInt, Vector3)>, + + pub watched_section: Vector3, } impl Player { @@ -103,8 +110,9 @@ impl Player { } } }; - + let config = client.config.clone().unwrap_or_default(); Self { + config, gameprofile, client, entity: Entity::new(entity_id, EntityType::Player, 1.62), @@ -123,6 +131,10 @@ impl Player { teleport_id_count: 0, abilities: PlayerAbilities::default(), gamemode, + watched_section: Vector3::new(0, 0, 0), + lastx: 0.0, + lasty: 0.0, + lastz: 0.0, } } @@ -185,11 +197,11 @@ impl Player { assert!(self.sneaking != sneaking); self.sneaking = sneaking; self.set_flag(Self::SNEAKING_FLAG_INDEX, sneaking).await; - if sneaking { - self.set_pose(EntityPose::Crouching).await; - } else { - self.set_pose(EntityPose::Standing).await; - } + // if sneaking { + // self.set_pose(EntityPose::Crouching).await; + // } else { + // self.set_pose(EntityPose::Standing).await; + // } } pub async fn set_sprinting(&mut self, sprinting: bool) { @@ -242,12 +254,10 @@ impl Player { self.teleport_id_count = 0; } let entity = &mut self.entity; - entity.x = x; - entity.y = y; - entity.z = z; - entity.lastx = x; - entity.lasty = y; - entity.lastz = z; + entity.set_pos(x, y, z); + self.lastx = x; + self.lasty = y; + self.lastz = z; entity.yaw = yaw; entity.pitch = pitch; self.awaiting_teleport = Some((self.teleport_id_count.into(), Vector3::new(x, y, z))); @@ -274,9 +284,9 @@ impl Player { let d = self.block_interaction_range() + additional_range; let box_pos = BoundingBox::from_block(pos); box_pos.squared_magnitude(Vector3 { - x: self.entity.x, - y: self.entity.y + self.entity.standing_eye_height as f64, - z: self.entity.z, + x: self.entity.pos.x, + y: self.entity.pos.y + self.entity.standing_eye_height as f64, + z: self.entity.pos.z, }) < d * d } @@ -441,13 +451,13 @@ impl Player { } } -#[derive(FromPrimitive)] +#[derive(FromPrimitive, Clone)] pub enum Hand { Main, Off, } -#[derive(FromPrimitive)] +#[derive(FromPrimitive, Clone)] pub enum ChatMode { Enabled, CommandsOnly, diff --git a/pumpkin/src/util/mod.rs b/pumpkin/src/util/mod.rs index 59887f233..8b1378917 100644 --- a/pumpkin/src/util/mod.rs +++ b/pumpkin/src/util/mod.rs @@ -1,2 +1 @@ -pub mod boundingbox; -pub mod math; + diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 77123a0ab..0672e049f 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -4,23 +4,25 @@ use std::{ sync::{Arc, Mutex, MutexGuard}, }; +pub mod player_chunker; + use mio::Token; use num_traits::ToPrimitive; use pumpkin_config::BasicConfiguration; +use pumpkin_core::math::vector2::Vector2; use pumpkin_entity::{entity_type::EntityType, EntityId}; use pumpkin_protocol::{ client::play::{ - CCenterChunk, CChunkData, CGameEvent, CLogin, CPlayerAbilities, CPlayerInfoUpdate, - CRemoveEntities, CRemovePlayerInfo, CSetEntityMetadata, CSpawnEntity, Metadata, - PlayerAction, + CChunkData, CGameEvent, CLogin, CPlayerAbilities, CPlayerInfoUpdate, CRemoveEntities, + CRemovePlayerInfo, CSetEntityMetadata, CSpawnEntity, Metadata, PlayerAction, }, uuid::UUID, ClientPacket, VarInt, }; -use pumpkin_world::{level::Level, radial_chunk_iterator::RadialIterator}; +use pumpkin_world::level::Level; use tokio::sync::mpsc; -use crate::entity::player::Player; +use crate::{client::Client, entity::player::Player}; pub struct World { pub level: Arc>, @@ -90,7 +92,7 @@ impl World { // TODO: this is for debug purpose, remove later player .client - .send_packet(&CPlayerAbilities::new(0x02, 0.1, 0.1)); + .send_packet(&CPlayerAbilities::new(0x02, 0.4, 0.1)); // teleport let x = 10.0; @@ -191,12 +193,12 @@ impl World { existing_player.entity_id().into(), UUID(gameprofile.id), (EntityType::Player as i32).into(), - entity.x, - entity.y, - entity.z, + entity.pos.x, + entity.pos.y, + entity.pos.z, entity.yaw, entity.pitch, - entity.pitch, + entity.head_yaw, 0.into(), 0.0, 0.0, @@ -214,26 +216,28 @@ impl World { self.broadcast_packet(&[&player.client.token], &packet) } - self.spawn_test_chunk(player, base_config.view_distance as u32) - .await; + // Spawn in inital chunks + player_chunker::player_join(self, player).await; } - async fn spawn_test_chunk(&self, player: &mut Player, distance: u32) { + async fn spawn_world_chunks( + &self, + client: &mut Client, + chunks: Vec>, + distance: i32, + ) { let inst = std::time::Instant::now(); let (sender, mut chunk_receiver) = mpsc::channel(distance as usize); - let chunks: Vec<_> = RadialIterator::new(distance).collect(); let level = self.level.clone(); tokio::spawn(async move { level.lock().unwrap().fetch_chunks(&chunks, sender); }); - player.client.send_packet(&CCenterChunk { - chunk_x: 0.into(), - chunk_z: 0.into(), - }); - while let Some(chunk_data) = chunk_receiver.recv().await { + if client.closed { + return; + } // dbg!(chunk_pos); let chunk_data = match chunk_data { Ok(d) => d, @@ -252,10 +256,9 @@ impl World { len / (1024 * 1024) ); } - player.client.send_packet(&CChunkData(&chunk_data)); + client.send_packet(&CChunkData(&chunk_data)); } - let t = inst.elapsed(); - dbg!("DONE", t); + dbg!("DONE CHUNKS", inst.elapsed()); } /// TODO: This definitly should be in world @@ -283,12 +286,10 @@ impl World { // todo: put this into the entitiy struct let id = player.entity_id(); let uuid = player.gameprofile.id; - dbg!("1"); self.broadcast_packet( &[&player.client.token], &CRemovePlayerInfo::new(1.into(), &[UUID(uuid)]), ); - dbg!("2"); self.broadcast_packet(&[&player.client.token], &CRemoveEntities::new(&[id.into()])) } } diff --git a/pumpkin/src/world/player_chunker.rs b/pumpkin/src/world/player_chunker.rs new file mode 100644 index 000000000..a060dfbd0 --- /dev/null +++ b/pumpkin/src/world/player_chunker.rs @@ -0,0 +1,102 @@ +use pumpkin_config::BASIC_CONFIG; +use pumpkin_core::math::{ + get_section_cord, position::WorldPosition, vector2::Vector2, vector3::Vector3, +}; +use pumpkin_protocol::client::play::{CCenterChunk, CUnloadChunk}; +use pumpkin_world::cylindrical_chunk_iterator::Cylindrical; + +use crate::entity::player::Player; + +use super::World; + +fn get_view_distance(player: &Player) -> i8 { + player + .config + .view_distance + .clamp(2, BASIC_CONFIG.view_distance as i8) +} + +pub async fn player_join(world: &World, player: &mut Player) { + let new_watched = chunk_section_from_pos(&player.entity.block_pos); + player.watched_section = new_watched; + let chunk_pos = player.entity.chunk_pos; + player.client.send_packet(&CCenterChunk { + chunk_x: chunk_pos.x.into(), + chunk_z: chunk_pos.z.into(), + }); + let view_distance = get_view_distance(player) as i32; + dbg!(view_distance); + let old_cylindrical = Cylindrical::new( + Vector2::new(player.watched_section.x, player.watched_section.z), + view_distance, + ); + let new_cylindrical = Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance); + let mut loading_chunks = Vec::new(); + Cylindrical::for_each_changed_chunk( + old_cylindrical, + new_cylindrical, + |chunk_pos| { + loading_chunks.push(chunk_pos); + }, + |chunk_pos| { + player + .client + .send_packet(&CUnloadChunk::new(chunk_pos.x, chunk_pos.z)); + }, + true, + ); + if !loading_chunks.is_empty() { + world + .spawn_world_chunks(&mut player.client, loading_chunks, view_distance) + .await; + } +} + +pub async fn update_position(world: &World, player: &mut Player) { + let current_watched = player.watched_section; + let new_watched = chunk_section_from_pos(&player.entity.block_pos); + if current_watched != new_watched { + let chunk_pos = player.entity.chunk_pos; + player.client.send_packet(&CCenterChunk { + chunk_x: chunk_pos.x.into(), + chunk_z: chunk_pos.z.into(), + }); + + let view_distance = get_view_distance(player) as i32; + let old_cylindrical = Cylindrical::new( + Vector2::new(player.watched_section.x, player.watched_section.z), + view_distance, + ); + let new_cylindrical = + Cylindrical::new(Vector2::new(chunk_pos.x, chunk_pos.z), view_distance); + player.watched_section = new_watched; + let mut loading_chunks = Vec::new(); + Cylindrical::for_each_changed_chunk( + old_cylindrical, + new_cylindrical, + |chunk_pos| { + loading_chunks.push(chunk_pos); + }, + |chunk_pos| { + player + .client + .send_packet(&CUnloadChunk::new(chunk_pos.x, chunk_pos.z)); + }, + false, + ); + if !loading_chunks.is_empty() { + world + .spawn_world_chunks(&mut player.client, loading_chunks, view_distance) + .await; + } + } +} + +fn chunk_section_from_pos(block_pos: &WorldPosition) -> Vector3 { + let block_pos = block_pos.0; + Vector3::new( + get_section_cord(block_pos.x), + get_section_cord(block_pos.y), + get_section_cord(block_pos.z), + ) +}