Merge pull request #68 from DaniD3v/master

Move config to lazy_lock and into own crate
This commit is contained in:
Alexander Medvedev
2024-09-01 09:07:28 +01:00
committed by GitHub
26 changed files with 392 additions and 359 deletions

13
Cargo.lock generated
View File

@@ -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"
@@ -1936,6 +1947,8 @@ dependencies = [
"colored",
"fastnbt",
"md5",
"num-derive",
"num-traits",
"serde",
"uuid",
]

View File

@@ -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"

12
pumpkin-config/Cargo.toml Normal file
View File

@@ -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

View File

@@ -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.

View File

@@ -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 }
}
}

View File

@@ -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,
}
}
}

176
pumpkin-config/src/lib.rs Normal file
View File

@@ -0,0 +1,176 @@
use log::warn;
use pumpkin_core::{Difficulty, GameMode};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{
fs,
net::{Ipv4Addr, SocketAddr},
path::Path,
sync::LazyLock,
};
pub mod auth;
pub mod proxy;
pub mod resource_pack;
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";
pub static ADVANCED_CONFIG: LazyLock<AdvancedConfiguration> =
LazyLock::new(AdvancedConfiguration::load);
pub static BASIC_CONFIG: LazyLock<BasicConfiguration> = LazyLock::new(BasicConfiguration::load);
/// 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, Default)]
pub struct AdvancedConfiguration {
pub proxy: ProxyConfig,
pub authentication: AuthenticationConfig,
pub packet_compression: CompressionConfig,
pub resource_pack: ResourcePackConfig,
pub commands: CommandsConfig,
pub rcon: RCONConfig,
pub pvp: PVPConfig,
}
#[derive(Serialize, Deserialize)]
pub struct BasicConfiguration {
/// A version identifier for the configuration format.
pub config_version: String,
/// The address to bind the server to.
pub server_address: SocketAddr,
/// The seed for world generation.
pub seed: String,
/// The maximum number of players allowed on the server.
pub max_players: u32,
/// The maximum view distance for players.
pub view_distance: u8,
/// The maximum simulated view distance.
pub simulation_distance: u8,
/// The default game difficulty.
pub default_difficulty: Difficulty,
/// Whether the Nether dimension is enabled.
pub allow_nether: bool,
/// Whether the server is in hardcore mode.
pub hardcore: bool,
/// Whether online mode is enabled. Requires valid Minecraft accounts.
pub online_mode: bool,
/// Whether packet encryption is enabled. Required when online mode is enabled.
pub encryption: bool,
/// The server's description displayed on the status screen.
pub motd: String,
/// The default game mode for players.
pub default_gamemode: GameMode,
}
impl Default for BasicConfiguration {
fn default() -> Self {
Self {
config_version: CURRENT_BASE_VERSION.to_string(),
server_address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25565),
seed: "".to_string(),
max_players: 100000,
view_distance: 10,
simulation_distance: 10,
default_difficulty: Difficulty::Normal,
allow_nether: true,
hardcore: false,
online_mode: true,
encryption: true,
motd: "A Blazing fast Pumpkin Server!".to_string(),
default_gamemode: GameMode::Survival,
}
}
}
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 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
}
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 LoadConfiguration for BasicConfiguration {
fn get_path() -> &'static Path {
Path::new("configuration.toml")
}
fn validate(&self) {
assert_eq!(
self.config_version, CURRENT_BASE_VERSION,
"Config version does not match used Config version. Please update your config"
);
assert!(self.view_distance >= 2, "View distance must be at least 2");
assert!(
self.view_distance <= 32,
"View distance must be less than 32"
);
if self.online_mode {
assert!(
self.encryption,
"When Online Mode is enabled, Encryption must be enabled"
)
}
}
}

27
pumpkin-config/src/pvp.rs Normal file
View File

@@ -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,
}
}
}

View File

@@ -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(),
}
}
}

View File

@@ -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" }

View File

@@ -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<Self, Self::Err> {
match s {
"survival" => Ok(Self::Survival),
"creative" => Ok(Self::Creative),
"adventure" => Ok(Self::Adventure),
"spectator" => Ok(Self::Spectator),
_ => Err(ParseGameModeError),
}
}
}

View File

@@ -1,2 +1,22 @@
pub mod gamemode;
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,
}
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ProfileAction {
ForcedNameChange,
UsingBannedSkin,
}

View File

@@ -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"}

View File

@@ -2,13 +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_config::TextureConfig, server::Server};
use crate::server::Server;
#[derive(Deserialize, Clone, Debug)]
#[allow(non_snake_case)]
@@ -29,14 +31,6 @@ pub struct Texture {
metadata: Option<HashMap<String, String>>,
}
#[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,
@@ -52,13 +46,9 @@ pub async fn authenticate(
ip: &IpAddr,
server: &mut Server,
) -> Result<GameProfile, AuthError> {
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}")

View File

@@ -1,4 +1,5 @@
use num_traits::FromPrimitive;
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
use pumpkin_core::text::TextComponent;
use pumpkin_protocol::{
client::{
@@ -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

View File

@@ -2,12 +2,13 @@ use std::f32::consts::PI;
use crate::{
commands::{handle_command, CommandSender},
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_config::ADVANCED_CONFIG;
use pumpkin_core::{text::TextComponent, GameMode};
use pumpkin_entity::EntityId;
use pumpkin_inventory::WindowType;
use pumpkin_protocol::server::play::{SCloseContainer, SSetPlayerGround, SUseItem};
@@ -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;

View File

@@ -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"];

View File

@@ -1,234 +0,0 @@
use std::path::Path;
use auth_config::AuthenticationConfig;
use proxy::ProxyConfig;
use resource_pack::ResourcePackConfig;
use serde::{Deserialize, Serialize};
use crate::{entity::player::GameMode, server::Difficulty};
pub mod auth_config;
pub mod proxy;
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.
/// This also allows you get some Performance or Resource boosts.
/// Important: The Configuration should match Vanilla by default
pub struct AdvancedConfiguration {
pub proxy: ProxyConfig,
pub authentication: AuthenticationConfig,
pub packet_compression: CompressionConfig,
pub resource_pack: ResourcePackConfig,
pub commands: CommandsConfig,
pub rcon: RCONConfig,
pub pvp: PVPConfig,
}
#[derive(Deserialize, Serialize, Clone)]
pub struct RCONConfig {
pub enabled: bool,
pub ip: String,
pub port: u16,
pub password: String,
}
impl Default for RCONConfig {
fn default() -> Self {
Self {
enabled: false,
ip: "0.0.0.0".to_string(),
port: 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,
}
}
}
/// 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.
pub config_version: String,
/// The address to bind the server to.
pub server_address: String,
/// The port to listen on.
pub server_port: u16,
/// The seed for world generation.
pub seed: String,
/// The maximum number of players allowed on the server.
pub max_players: u32,
/// The maximum view distance for players.
pub view_distance: u8,
/// The maximum simulated view distance.
pub simulation_distance: u8,
/// The default game difficulty.
pub default_difficulty: Difficulty,
/// Whether the Nether dimension is enabled.
pub allow_nether: bool,
/// Whether the server is in hardcore mode.
pub hardcore: bool,
/// Whether online mode is enabled. Requires valid Minecraft accounts.
pub online_mode: bool,
/// Whether packet encryption is enabled. Required when online mode is enabled.
pub encryption: bool,
/// The server's description displayed on the status screen.
pub motd: String,
/// The default game mode for players.
pub default_gamemode: GameMode,
}
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,
seed: "".to_string(),
max_players: 100000,
view_distance: 10,
simulation_distance: 10,
default_difficulty: Difficulty::Normal,
allow_nether: true,
hardcore: false,
online_mode: true,
encryption: true,
motd: "A Blazing fast Pumpkin Server!".to_string(),
default_gamemode: GameMode::Survival,
}
}
}
impl AdvancedConfiguration {
pub fn load<P: AsRef<Path>>(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
} 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
}
}
pub fn validate(&self) {
self.resource_pack.validate()
}
}
impl BasicConfiguration {
pub fn load<P: AsRef<Path>>(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
}
}
pub fn validate(&self) {
assert_eq!(
self.config_version, CURRENT_BASE_VERSION,
"Config version does not match used Config version. Please update your config"
);
assert!(self.view_distance >= 2, "View distance must be at least 2");
assert!(
self.view_distance <= 32,
"View distance must be less than 32"
);
if self.online_mode {
assert!(
self.encryption,
"When Online Mode is enabled, Encryption must be enabled"
)
}
}
}

View File

@@ -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<Self, Self::Err> {
match s {
"survival" => Ok(Self::Survival),
"creative" => Ok(Self::Creative),
"adventure" => Ok(Self::Adventure),
"spectator" => Ok(Self::Spectator),
_ => Err(ParseGameModeError),
}
}
}

View File

@@ -6,23 +6,18 @@ 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 server::Server;
// Setup some tokens to allow us to identify which event is for which socket.
pub mod client;
pub mod commands;
pub mod config;
pub mod entity;
pub mod proxy;
pub mod rcon;
@@ -34,6 +29,7 @@ fn main() -> io::Result<()> {
use std::sync::{Arc, Mutex};
use entity::player::Player;
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
use pumpkin_core::text::{color::NamedColor, TextComponent};
use rcon::RCONServer;
@@ -64,9 +60,6 @@ fn main() -> io::Result<()> {
use std::time::Instant;
let time = Instant::now();
let basic_config = BasicConfiguration::load("configuration.toml");
let advanced_configuration = AdvancedConfiguration::load("features.toml");
// Create a poll instance.
let mut poll = Poll::new()?;
@@ -74,14 +67,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.
@@ -91,16 +77,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<Token, Client> = HashMap::new();
let mut players: HashMap<Arc<Token>, Arc<Mutex<Player>>> = 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);
@@ -214,7 +197,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;
}
}
}

View File

@@ -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<Sha256>;

View File

@@ -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;
@@ -35,11 +36,8 @@ impl RCONServer {
server: Arc<tokio::sync::Mutex<Server>>,
) -> Result<Self, io::Error> {
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)

View File

@@ -11,6 +11,8 @@ 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;
use pumpkin_protocol::{
@@ -21,14 +23,8 @@ use pumpkin_world::dimension::Dimension;
use pumpkin_registry::Registry;
use rsa::{traits::PublicKeyParts, RsaPrivateKey, RsaPublicKey};
use serde::{Deserialize, Serialize};
use crate::{
client::Client,
config::{AdvancedConfiguration, BasicConfiguration},
entity::player::{GameMode, Player},
world::World,
};
use crate::{client::Client, entity::player::Player, world::World};
pub const CURRENT_MC_VERSION: &str = "1.21.1";
@@ -52,16 +48,15 @@ pub struct Server {
pub cached_registry: Vec<Registry>,
entity_id: AtomicI32,
pub base_config: BasicConfiguration,
pub advanced_config: AdvancedConfiguration,
/// Used for Authentication, None is Online mode is disabled
pub auth_client: Option<reqwest::Client>,
}
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 +70,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 +101,7 @@ impl Server {
status_response,
status_response_json,
public_key_der,
base_config: config.0,
auth_client,
advanced_config: config.1,
}
}
@@ -118,7 +111,7 @@ impl Server {
client: Client,
) -> (Arc<Mutex<Player>>, Arc<tokio::sync::Mutex<World>>) {
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,
};
@@ -216,11 +209,3 @@ impl Server {
(pub_key, priv_key)
}
}
#[derive(PartialEq, Serialize, Deserialize)]
pub enum Difficulty {
Peaceful,
Easy,
Normal,
Hard,
}

View File

@@ -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<Mutex<Level>>,