Merge branch 'songtronix/add-server-config' into 'master'

Add server config

Closes #173

See merge request veloren/veloren!277
This commit is contained in:
Forest Anderson 2019-07-17 17:11:56 +00:00
commit e912b96332
16 changed files with 137 additions and 28 deletions

1
.gitignore vendored
View File

@ -31,5 +31,6 @@
# Veloren
*.rar
*.log
settings.ron
run.sh
screenshots

3
Cargo.lock generated
View File

@ -2766,7 +2766,10 @@ version = "0.2.0"
dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scan_fmt 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
"specs 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)",
"uvth 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"vek 0.9.8 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -6,6 +6,8 @@ pub enum Error {
ServerWentMad,
ServerTimeout,
ServerShutdown,
TooManyPlayers,
//TODO: InvalidAlias,
Other(String),
}

View File

@ -9,7 +9,7 @@ pub use specs::Entity as EcsEntity;
use common::{
comp,
msg::{ClientMsg, ClientState, ServerInfo, ServerMsg},
msg::{ClientMsg, ClientState, ServerError, ServerInfo, ServerMsg},
net::PostBox,
state::State,
terrain::{block::Block, chonk::ChonkMetrics, TerrainChunk, TerrainChunkSize},
@ -73,6 +73,9 @@ impl Client {
.ok_or(Error::ServerWentMad)?;
(state, entity, server_info)
}
Some(ServerMsg::Error(ServerError::TooManyPlayers)) => {
return Err(Error::TooManyPlayers)
}
_ => return Err(Error::ServerWentMad),
};
@ -361,8 +364,12 @@ impl Client {
if new_msgs.len() > 0 {
for msg in new_msgs {
match msg {
ServerMsg::InitialSync { .. } => return Err(Error::ServerWentMad),
ServerMsg::Error(e) => match e {
ServerError::TooManyPlayers => return Err(Error::ServerWentMad),
//TODO: ServerError::InvalidAlias => return Err(Error::InvalidAlias),
},
ServerMsg::Shutdown => return Err(Error::ServerShutdown),
ServerMsg::InitialSync { .. } => return Err(Error::ServerWentMad),
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
ServerMsg::Pong => {
self.last_ping_delta = Instant::now()

View File

@ -19,7 +19,6 @@ impl Player {
pub fn is_valid(&self) -> bool {
self.alias.chars().all(|c| c.is_alphanumeric() || c == '_')
&& self.alias.len() <= MAX_ALIAS_LEN
// TODO: Check view distance here based on server config too
}
}

View File

@ -5,7 +5,7 @@ pub mod server;
// Reexports
pub use self::client::ClientMsg;
pub use self::ecs_packet::{EcsCompPacket, EcsResPacket};
pub use self::server::{RequestStateError, ServerInfo, ServerMsg};
pub use self::server::{RequestStateError, ServerError, ServerInfo, ServerMsg};
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum ClientState {

View File

@ -41,6 +41,13 @@ pub enum ServerMsg {
key: Vec2<i32>,
chunk: Box<TerrainChunk>,
},
Error(ServerError),
Disconnect,
Shutdown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ServerError {
TooManyPlayers,
//TODO: InvalidAlias,
}

View File

@ -9,4 +9,4 @@ server = { package = "veloren-server", path = "../server" }
common = { package = "veloren-common", path = "../common" }
log = "0.4"
pretty_env_logger = "0.3"
pretty_env_logger = "0.3"

View File

@ -1,6 +1,6 @@
use common::clock::Clock;
use log::info;
use server::{Event, Input, Server};
use server::{Event, Input, Server, ServerSettings};
use std::time::Duration;
const TPS: u64 = 30;
@ -14,8 +14,11 @@ fn main() {
// Set up an fps clock
let mut clock = Clock::start();
// Load settings
let settings = ServerSettings::load();
// Create server
let mut server = Server::new().expect("Failed to create server instance!");
let mut server = Server::new(settings).expect("Failed to create server instance!");
loop {
let events = server

View File

@ -14,3 +14,6 @@ vek = "0.9"
uvth = "3.1.0"
lazy_static = "1.3.0"
scan_fmt = "0.1.3"
ron = "0.5.1"
serde = "1.0"
serde_derive = "1.0"

View File

@ -41,6 +41,10 @@ impl Clients {
}
}
pub fn len(&mut self) -> usize {
self.clients.len()
}
pub fn add(&mut self, entity: EcsEntity, client: Client) {
self.clients.insert(entity, client);
}

View File

@ -4,9 +4,10 @@ pub mod client;
pub mod cmd;
pub mod error;
pub mod input;
pub mod settings;
// Reexports
pub use crate::{error::Error, input::Input};
pub use crate::{error::Error, input::Input, settings::ServerSettings};
use crate::{
client::{Client, Clients},
@ -14,9 +15,9 @@ use crate::{
};
use common::{
comp,
msg::{ClientMsg, ClientState, RequestStateError, ServerInfo, ServerMsg},
msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg},
net::PostOffice,
state::{State, TerrainChange, Uid},
state::{State, TerrainChange, TimeOfDay, Uid},
terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainMap},
vol::VolSize,
vol::Vox,
@ -36,8 +37,6 @@ use world::World;
const CLIENT_TIMEOUT: f64 = 20.0; // Seconds
const DEFAULT_WORLD_SEED: u32 = 1337;
pub enum Event {
ClientConnected {
entity: EcsEntity,
@ -66,19 +65,20 @@ pub struct Server {
chunk_rx: mpsc::Receiver<(Vec2<i32>, TerrainChunk)>,
pending_chunks: HashSet<Vec2<i32>>,
server_settings: ServerSettings,
server_info: ServerInfo,
}
impl Server {
/// Create a new `Server` bound to the default socket.
#[allow(dead_code)]
pub fn new() -> Result<Self, Error> {
Self::bind(SocketAddr::from(([0; 4], 59003)))
pub fn new(settings: ServerSettings) -> Result<Self, Error> {
Self::bind(settings.address, settings)
}
/// Create a new server bound to the given socket.
#[allow(dead_code)]
pub fn bind<A: Into<SocketAddr>>(addrs: A) -> Result<Self, Error> {
pub fn bind<A: Into<SocketAddr>>(addrs: A, settings: ServerSettings) -> Result<Self, Error> {
let (chunk_tx, chunk_rx) = mpsc::channel();
let mut state = State::default();
@ -86,9 +86,12 @@ impl Server {
.ecs_mut()
.add_resource(SpawnPoint(Vec3::new(16_384.0, 16_384.0, 380.0)));
// Set starting time for the server.
state.ecs_mut().write_resource::<TimeOfDay>().0 = settings.start_time;
let this = Self {
state,
world: Arc::new(World::generate(DEFAULT_WORLD_SEED)),
world: Arc::new(World::generate(settings.world_seed)),
postoffice: PostOffice::bind(addrs.into())?,
clients: Clients::empty(),
@ -101,9 +104,10 @@ impl Server {
pending_chunks: HashSet::new(),
server_info: ServerInfo {
name: "Server name".to_owned(),
description: "This is the best Veloren server.".to_owned(),
name: settings.server_name.clone(),
description: settings.server_description.clone(),
},
server_settings: settings,
};
Ok(this)
@ -356,16 +360,20 @@ impl Server {
last_ping: self.state.get_time(),
};
// Return the state of the current world (all of the components that Sphynx tracks).
client.notify(ServerMsg::InitialSync {
ecs_state: self.state.ecs().gen_state_package(),
entity_uid: self.state.ecs().uid_from_entity(entity).unwrap().into(), // Can't fail.
server_info: self.server_info.clone(),
});
if self.server_settings.max_players <= self.clients.len() {
client.notify(ServerMsg::Error(ServerError::TooManyPlayers));
} else {
// Return the state of the current world (all of the components that Sphynx tracks).
client.notify(ServerMsg::InitialSync {
ecs_state: self.state.ecs().gen_state_package(),
entity_uid: self.state.ecs().uid_from_entity(entity).unwrap().into(), // Can't fail.
server_info: self.server_info.clone(),
});
frontend_events.push(Event::ClientConnected { entity });
}
self.clients.add(entity, client);
frontend_events.push(Event::ClientConnected { entity });
}
Ok(frontend_events)

65
server/src/settings.rs Normal file
View File

@ -0,0 +1,65 @@
use serde_derive::{Deserialize, Serialize};
use std::{fs, io::prelude::*, net::SocketAddr, path::PathBuf};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct ServerSettings {
pub address: SocketAddr,
pub max_players: usize,
pub world_seed: u32,
//pub pvp_enabled: bool,
pub server_name: String,
pub server_description: String,
//pub login_server: whatever
pub start_time: f64,
}
impl Default for ServerSettings {
fn default() -> Self {
Self {
address: SocketAddr::from(([0; 4], 59003)),
world_seed: 1337,
server_name: "Server name".to_owned(),
server_description: "This is the best Veloren server.".to_owned(),
max_players: 16,
start_time: 0.0,
}
}
}
impl ServerSettings {
pub fn load() -> Self {
let path = ServerSettings::get_settings_path();
if let Ok(file) = fs::File::open(path) {
match ron::de::from_reader(file) {
Ok(x) => x,
Err(e) => {
log::warn!("Failed to parse setting file! Fallback to default. {}", e);
Self::default()
}
}
} else {
let default_settings = Self::default();
match default_settings.save_to_file() {
Err(e) => log::error!("Failed to create default setting file! {}", e),
_ => {}
}
default_settings
}
}
pub fn save_to_file(&self) -> std::io::Result<()> {
let path = ServerSettings::get_settings_path();
let mut config_file = fs::File::create(path)?;
let s: &str = &ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap();
config_file.write_all(s.as_bytes()).unwrap();
Ok(())
}
fn get_settings_path() -> PathBuf {
PathBuf::from(r"settings.ron")
}
}

View File

@ -20,6 +20,7 @@ pub enum Error {
// Parsing/host name resolution successful but could not connect.
ConnectionFailed(ClientError),
ClientCrashed,
ServerIsFull,
}
// Used to asynchronously parse the server address, resolve host names,
@ -76,6 +77,10 @@ impl ClientInit {
ClientError::Network(_) => {
last_err = Some(Error::ConnectionFailed(err))
}
ClientError::TooManyPlayers => {
last_err = Some(Error::ServerIsFull);
break;
}
// TODO: Handle errors?
_ => panic!(
"Unexpected non-network error when creating client: {:?}",

View File

@ -64,6 +64,7 @@ impl PlayState for MainMenuState {
self.main_menu_ui.login_error(
match err {
InitError::BadAddress(_) | InitError::NoAddress => "Server not found",
InitError::ServerIsFull => "Server is Full!",
InitError::ConnectionFailed(_) => "Connection failed",
InitError::ClientCrashed => "Client crashed",
}

View File

@ -2,7 +2,7 @@ use client::Client;
use common::clock::Clock;
use log::info;
use portpicker::pick_unused_port;
use server::{Event, Input, Server};
use server::{Event, Input, Server, ServerSettings};
use std::{
net::SocketAddr,
sync::mpsc::{channel, Receiver, Sender, TryRecvError},
@ -36,7 +36,8 @@ impl Singleplayer {
));
// Create server
let server = Server::bind(sock.clone()).expect("Failed to create server instance!");
let server = Server::bind(sock.clone(), ServerSettings::default())
.expect("Failed to create server instance!");
let server = match client {
Some(client) => server.with_thread_pool(client.thread_pool().clone()),