mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added server-side maximum view distance setting
This commit is contained in:
parent
6501611372
commit
b46e080ade
@ -62,6 +62,7 @@ pub enum Event {
|
||||
Disconnect,
|
||||
DisconnectionNotification(u64),
|
||||
Notification(Notification),
|
||||
SetViewDistance(u32),
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
@ -924,6 +925,10 @@ impl Client {
|
||||
self.clean_state();
|
||||
self.character_list.error = Some(error);
|
||||
},
|
||||
ServerMsg::SetViewDistance(vd) => {
|
||||
self.view_distance = Some(vd);
|
||||
frontend_events.push(Event::SetViewDistance(vd));
|
||||
},
|
||||
}
|
||||
}
|
||||
} else if let Some(err) = self.postbox.error() {
|
||||
|
@ -87,6 +87,7 @@ pub enum ServerMsg {
|
||||
TooManyPlayers,
|
||||
/// Send a popup notification such as "Waypoint Saved"
|
||||
Notification(Notification),
|
||||
SetViewDistance(u32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
|
@ -14,7 +14,7 @@ world = { package = "veloren-world", path = "../world" }
|
||||
|
||||
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git" }
|
||||
|
||||
tracing = { version = "0.1", default-features = false }
|
||||
tracing = { version = "0.1", default-features = true }
|
||||
specs = { version = "0.15.1", features = ["shred-derive"] }
|
||||
vek = "0.11.0"
|
||||
uvth = "3.1.1"
|
||||
|
@ -1,4 +1,8 @@
|
||||
use crate::{sys, Server, StateExt};
|
||||
use crate::{
|
||||
sys,
|
||||
Server,
|
||||
StateExt,
|
||||
};
|
||||
use common::{
|
||||
comp::{
|
||||
self, Agent, Alignment, Body, Gravity, Item, ItemDrop, LightEmitter, Loadout, Pos,
|
||||
@ -10,10 +14,7 @@ use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||
use vek::{Rgb, Vec3};
|
||||
|
||||
pub fn handle_initialize_character(server: &mut Server, entity: EcsEntity, character_id: i32) {
|
||||
let state = &mut server.state;
|
||||
let server_settings = &server.server_settings;
|
||||
|
||||
state.initialize_character_data(entity, character_id, server_settings);
|
||||
server.state.initialize_character_data(entity, character_id);
|
||||
}
|
||||
|
||||
pub fn handle_loaded_character_data(
|
||||
@ -21,10 +22,8 @@ pub fn handle_loaded_character_data(
|
||||
entity: EcsEntity,
|
||||
loaded_components: (comp::Body, comp::Stats, comp::Inventory, comp::Loadout),
|
||||
) {
|
||||
let state = &mut server.state;
|
||||
|
||||
state.update_character_data(entity, loaded_components);
|
||||
sys::subscription::initialize_region_subscription(state.ecs(), entity);
|
||||
server.state.update_character_data(entity, loaded_components);
|
||||
sys::subscription::initialize_region_subscription(server.state.ecs(), entity);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![deny(unsafe_code)]
|
||||
#![allow(clippy::option_map_unit_fn)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(drain_filter, option_zip)]
|
||||
|
||||
pub mod auth_provider;
|
||||
pub mod chunk_generator;
|
||||
@ -83,8 +83,6 @@ pub struct Server {
|
||||
server_info: ServerInfo,
|
||||
metrics: ServerMetrics,
|
||||
tick_metrics: TickMetrics,
|
||||
|
||||
server_settings: ServerSettings,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
@ -93,6 +91,7 @@ impl Server {
|
||||
#[allow(clippy::needless_update)] // TODO: Pending review in #587
|
||||
pub fn new(settings: ServerSettings) -> Result<Self, Error> {
|
||||
let mut state = State::default();
|
||||
state.ecs_mut().insert(settings.clone());
|
||||
state.ecs_mut().insert(EventBus::<ServerEvent>::default());
|
||||
state.ecs_mut().insert(AuthProvider::new(
|
||||
settings.auth_server_address.clone(),
|
||||
@ -247,13 +246,12 @@ impl Server {
|
||||
},
|
||||
metrics,
|
||||
tick_metrics,
|
||||
server_settings: settings.clone(),
|
||||
};
|
||||
|
||||
// Run pending DB migrations (if any)
|
||||
debug!("Running DB migrations...");
|
||||
|
||||
if let Some(e) = persistence::run_migrations(&this.server_settings.persistence_db_dir).err()
|
||||
if let Some(e) = persistence::run_migrations(&settings.persistence_db_dir).err()
|
||||
{
|
||||
info!(?e, "Migration error");
|
||||
}
|
||||
@ -575,7 +573,7 @@ impl Server {
|
||||
login_msg_sent: false,
|
||||
};
|
||||
|
||||
if self.server_settings.max_players
|
||||
if self.state.ecs().fetch::<ServerSettings>().max_players
|
||||
<= self.state.ecs().read_storage::<Client>().join().count()
|
||||
{
|
||||
// Note: in this case the client is dropped
|
||||
|
@ -24,6 +24,7 @@ pub struct ServerSettings {
|
||||
/// uses the value of the file options to decide how to proceed.
|
||||
pub map_file: Option<FileOpts>,
|
||||
pub persistence_db_dir: String,
|
||||
pub max_view_distance: Option<u32>,
|
||||
}
|
||||
|
||||
impl Default for ServerSettings {
|
||||
@ -61,6 +62,7 @@ impl Default for ServerSettings {
|
||||
.collect(),
|
||||
whitelist: Vec::new(),
|
||||
persistence_db_dir: "saves".to_owned(),
|
||||
max_view_distance: Some(30),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,6 @@ pub trait StateExt {
|
||||
&mut self,
|
||||
entity: EcsEntity,
|
||||
character_id: i32,
|
||||
server_settings: &ServerSettings,
|
||||
);
|
||||
/// Update the components associated with the entity's current character.
|
||||
/// Performed after loading component data from the database
|
||||
@ -161,7 +160,6 @@ impl StateExt for State {
|
||||
&mut self,
|
||||
entity: EcsEntity,
|
||||
character_id: i32,
|
||||
server_settings: &ServerSettings,
|
||||
) {
|
||||
let spawn_point = self.ecs().read_resource::<SpawnPoint>().0;
|
||||
|
||||
@ -192,7 +190,7 @@ impl StateExt for State {
|
||||
});
|
||||
|
||||
// Give the Admin component to the player if their name exists in admin list
|
||||
if server_settings.admins.contains(
|
||||
if self.ecs().fetch::<ServerSettings>().admins.contains(
|
||||
&self
|
||||
.ecs()
|
||||
.read_storage::<comp::Player>()
|
||||
|
@ -1,6 +1,7 @@
|
||||
use super::SysTimer;
|
||||
use crate::{
|
||||
auth_provider::AuthProvider, client::Client, persistence::character::CharacterLoader,
|
||||
ServerSettings,
|
||||
CLIENT_TIMEOUT,
|
||||
};
|
||||
use common::{
|
||||
@ -15,8 +16,8 @@ use common::{
|
||||
},
|
||||
state::{BlockChange, Time},
|
||||
sync::Uid,
|
||||
terrain::{Block, TerrainGrid},
|
||||
vol::Vox,
|
||||
terrain::{Block, TerrainGrid, TerrainChunkSize},
|
||||
vol::{Vox, RectVolSize},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use specs::{
|
||||
@ -49,6 +50,7 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Client>,
|
||||
WriteStorage<'a, Controller>,
|
||||
WriteStorage<'a, SpeechBubble>,
|
||||
Read<'a, ServerSettings>,
|
||||
);
|
||||
|
||||
#[allow(clippy::match_ref_pats)] // TODO: Pending review in #587
|
||||
@ -77,6 +79,7 @@ impl<'a> System<'a> for Sys {
|
||||
mut clients,
|
||||
mut controllers,
|
||||
mut speech_bubbles,
|
||||
settings,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
timer.start();
|
||||
@ -156,7 +159,8 @@ impl<'a> System<'a> for Sys {
|
||||
Ok((username, uuid)) => (username, uuid),
|
||||
};
|
||||
|
||||
let player = Player::new(username, None, view_distance, uuid);
|
||||
let vd = view_distance.map(|vd| vd.min(settings.max_view_distance.unwrap_or(vd)));
|
||||
let player = Player::new(username, None, vd, uuid);
|
||||
|
||||
if !player.is_valid() {
|
||||
// Invalid player
|
||||
@ -184,12 +188,26 @@ impl<'a> System<'a> for Sys {
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
}
|
||||
//client.allow_state(ClientState::Registered);
|
||||
|
||||
// Limit view distance if it's too high
|
||||
// This comes after state registration so that the client actually hears it
|
||||
if settings.max_view_distance.zip(view_distance).map(|(vd, max)| vd > max).unwrap_or(false) {
|
||||
client.notify(ServerMsg::SetViewDistance(settings.max_view_distance.unwrap_or(0)));
|
||||
};
|
||||
},
|
||||
ClientMsg::SetViewDistance(view_distance) => match client.client_state {
|
||||
ClientState::Character { .. } => {
|
||||
players
|
||||
.get_mut(entity)
|
||||
.map(|player| player.view_distance = Some(view_distance));
|
||||
if settings.max_view_distance.map(|max| view_distance <= max).unwrap_or(true) {
|
||||
players
|
||||
.get_mut(entity)
|
||||
.map(|player| player.view_distance = Some(
|
||||
settings.max_view_distance
|
||||
.map(|max| view_distance.min(max))
|
||||
.unwrap_or(view_distance)
|
||||
));
|
||||
} else {
|
||||
client.notify(ServerMsg::SetViewDistance(settings.max_view_distance.unwrap_or(0)));
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
@ -323,14 +341,26 @@ impl<'a> System<'a> for Sys {
|
||||
client.error_state(RequestStateError::Impossible);
|
||||
},
|
||||
ClientState::Spectator | ClientState::Character => {
|
||||
match terrain.get_key(key) {
|
||||
Some(chunk) => {
|
||||
client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Ok(Box::new(chunk.clone())),
|
||||
})
|
||||
},
|
||||
None => server_emitter.emit(ServerEvent::ChunkRequest(entity, key)),
|
||||
let in_vd = if let (Some(view_distance), Some(pos)) = (
|
||||
players.get(entity).and_then(|p| p.view_distance),
|
||||
positions.get(entity),
|
||||
) {
|
||||
pos.0.xy().map(|e| e as f64).distance(key.map(|e| e as f64 + 0.5) * TerrainChunkSize::RECT_SIZE.map(|e| e as f64)) < (view_distance as f64 + 1.0) * TerrainChunkSize::RECT_SIZE.x as f64
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if in_vd {
|
||||
match terrain.get_key(key) {
|
||||
Some(chunk) => {
|
||||
client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Ok(Box::new(chunk.clone())),
|
||||
})
|
||||
},
|
||||
None => server_emitter.emit(ServerEvent::ChunkRequest(entity, key)),
|
||||
}
|
||||
} else {
|
||||
warn!("Not in VD!");
|
||||
}
|
||||
},
|
||||
ClientState::Pending => {},
|
||||
|
@ -75,7 +75,7 @@ impl SessionState {
|
||||
|
||||
impl SessionState {
|
||||
/// Tick the session (and the client attached to it).
|
||||
fn tick(&mut self, dt: Duration) -> Result<TickAction, Error> {
|
||||
fn tick(&mut self, dt: Duration, global_state: &mut GlobalState) -> Result<TickAction, Error> {
|
||||
self.inputs.tick(dt);
|
||||
|
||||
for event in self.client.borrow_mut().tick(
|
||||
@ -107,6 +107,10 @@ impl SessionState {
|
||||
self.hud
|
||||
.new_message(client::Event::Notification(Notification::WaypointSaved));
|
||||
},
|
||||
client::Event::SetViewDistance(vd) => {
|
||||
global_state.settings.graphics.view_distance = vd;
|
||||
global_state.settings.save_to_file_warn();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -535,7 +539,7 @@ impl PlayState for SessionState {
|
||||
|| !global_state.singleplayer.as_ref().unwrap().is_paused()
|
||||
{
|
||||
// Perform an in-game tick.
|
||||
match self.tick(clock.get_avg_delta()) {
|
||||
match self.tick(clock.get_avg_delta(), global_state) {
|
||||
Ok(TickAction::Continue) => {}, // Do nothing
|
||||
Ok(TickAction::Disconnect) => return PlayStateResult::Pop, // Go to main menu
|
||||
Err(err) => {
|
||||
|
Loading…
Reference in New Issue
Block a user