mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/vd-cap' into 'master'
View distance cap, MOTD on login See merge request veloren/veloren!1112
This commit is contained in:
commit
9e5f03e2f4
12
CHANGELOG.md
12
CHANGELOG.md
@ -10,25 +10,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Added context-sensitive crosshair
|
- Added context-sensitive crosshair
|
||||||
- Announce alias changes to all clients.
|
- Announce alias changes to all clients
|
||||||
- Dance animation
|
- Dance animation
|
||||||
- Speech bubbles appear when nearby players talk
|
- Speech bubbles appear when nearby players talk
|
||||||
- NPCs call for help when attacked
|
- NPCs call for help when attacked
|
||||||
- Eyebrows and shapes can now be selected
|
- Eyebrows and shapes can now be selected
|
||||||
- Character name and level information to chat, social tab and `/players` command.
|
- Character name and level information to chat, social tab and `/players` command
|
||||||
- Added inventory, armour and weapon saving
|
- Added inventory, armour and weapon saving
|
||||||
- Show where screenshots are saved to in the chat
|
- Show where screenshots are saved to in the chat
|
||||||
- Added basic auto walk
|
- Added basic auto walk
|
||||||
- Added weapon/attack sound effects
|
- Added weapon/attack sound effects
|
||||||
- M2 attack for bow
|
- M2 attack for bow
|
||||||
- Hotbar persistence.
|
- Hotbar persistence
|
||||||
- Alpha version Disclaimer
|
- Alpha version Disclaimer
|
||||||
- Server whitelist
|
- Server whitelist
|
||||||
|
- Optional server-side maximum view distance
|
||||||
|
- MOTD on login
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Improved camera aiming
|
- Improved camera aiming
|
||||||
- Made civsim, sites, etc. deterministic from the same seed.
|
- Made civsim, sites, etc. deterministic from the same seed
|
||||||
- Improved animations by adding orientation variation
|
- Improved animations by adding orientation variation
|
||||||
- new tail bone for quad_small body
|
- new tail bone for quad_small body
|
||||||
- slim the game size through lossless asset optimization
|
- slim the game size through lossless asset optimization
|
||||||
@ -43,7 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Wield requirement to swap loadout; fixes issue with unable swap loadout outside of combat.
|
- Wield requirement to swap loadout; fixes issue with unable swap loadout outside of combat
|
||||||
- Disclaimer wall of text on first startup
|
- Disclaimer wall of text on first startup
|
||||||
|
|
||||||
## [0.6.0] - 2020-05-16
|
## [0.6.0] - 2020-05-16
|
||||||
|
@ -94,7 +94,7 @@ fn main() {
|
|||||||
|
|
||||||
println!("{}", message)
|
println!("{}", message)
|
||||||
},
|
},
|
||||||
Event::Notification(_) => {}, // TODO?
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ pub enum Event {
|
|||||||
Disconnect,
|
Disconnect,
|
||||||
DisconnectionNotification(u64),
|
DisconnectionNotification(u64),
|
||||||
Notification(Notification),
|
Notification(Notification),
|
||||||
|
SetViewDistance(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
@ -924,6 +925,10 @@ impl Client {
|
|||||||
self.clean_state();
|
self.clean_state();
|
||||||
self.character_list.error = Some(error);
|
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() {
|
} else if let Some(err) = self.postbox.error() {
|
||||||
|
@ -43,10 +43,12 @@ pub enum ChatCommand {
|
|||||||
KillNpcs,
|
KillNpcs,
|
||||||
Lantern,
|
Lantern,
|
||||||
Light,
|
Light,
|
||||||
|
Motd,
|
||||||
Object,
|
Object,
|
||||||
Players,
|
Players,
|
||||||
RemoveLights,
|
RemoveLights,
|
||||||
SetLevel,
|
SetLevel,
|
||||||
|
SetMotd,
|
||||||
Spawn,
|
Spawn,
|
||||||
Sudo,
|
Sudo,
|
||||||
Tell,
|
Tell,
|
||||||
@ -74,10 +76,12 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[
|
|||||||
ChatCommand::KillNpcs,
|
ChatCommand::KillNpcs,
|
||||||
ChatCommand::Lantern,
|
ChatCommand::Lantern,
|
||||||
ChatCommand::Light,
|
ChatCommand::Light,
|
||||||
|
ChatCommand::Motd,
|
||||||
ChatCommand::Object,
|
ChatCommand::Object,
|
||||||
ChatCommand::Players,
|
ChatCommand::Players,
|
||||||
ChatCommand::RemoveLights,
|
ChatCommand::RemoveLights,
|
||||||
ChatCommand::SetLevel,
|
ChatCommand::SetLevel,
|
||||||
|
ChatCommand::SetMotd,
|
||||||
ChatCommand::Spawn,
|
ChatCommand::Spawn,
|
||||||
ChatCommand::Sudo,
|
ChatCommand::Sudo,
|
||||||
ChatCommand::Tell,
|
ChatCommand::Tell,
|
||||||
@ -224,6 +228,7 @@ impl ChatCommand {
|
|||||||
"Spawn entity with light",
|
"Spawn entity with light",
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
|
ChatCommand::Motd => cmd(vec![Message], "View the server description", false),
|
||||||
ChatCommand::Object => cmd(
|
ChatCommand::Object => cmd(
|
||||||
vec![Enum("object", OBJECTS.clone(), Required)],
|
vec![Enum("object", OBJECTS.clone(), Required)],
|
||||||
"Spawn an object",
|
"Spawn an object",
|
||||||
@ -240,6 +245,7 @@ impl ChatCommand {
|
|||||||
"Set player Level",
|
"Set player Level",
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
|
ChatCommand::SetMotd => cmd(vec![Message], "Set the server description", true),
|
||||||
ChatCommand::Spawn => cmd(
|
ChatCommand::Spawn => cmd(
|
||||||
vec![
|
vec![
|
||||||
Enum("alignment", ALIGNMENTS.clone(), Required),
|
Enum("alignment", ALIGNMENTS.clone(), Required),
|
||||||
@ -295,10 +301,12 @@ impl ChatCommand {
|
|||||||
ChatCommand::KillNpcs => "kill_npcs",
|
ChatCommand::KillNpcs => "kill_npcs",
|
||||||
ChatCommand::Lantern => "lantern",
|
ChatCommand::Lantern => "lantern",
|
||||||
ChatCommand::Light => "light",
|
ChatCommand::Light => "light",
|
||||||
|
ChatCommand::Motd => "motd",
|
||||||
ChatCommand::Object => "object",
|
ChatCommand::Object => "object",
|
||||||
ChatCommand::Players => "players",
|
ChatCommand::Players => "players",
|
||||||
ChatCommand::RemoveLights => "remove_lights",
|
ChatCommand::RemoveLights => "remove_lights",
|
||||||
ChatCommand::SetLevel => "set_level",
|
ChatCommand::SetLevel => "set_level",
|
||||||
|
ChatCommand::SetMotd => "set_motd",
|
||||||
ChatCommand::Spawn => "spawn",
|
ChatCommand::Spawn => "spawn",
|
||||||
ChatCommand::Sudo => "sudo",
|
ChatCommand::Sudo => "sudo",
|
||||||
ChatCommand::Tell => "tell",
|
ChatCommand::Tell => "tell",
|
||||||
|
@ -87,6 +87,7 @@ pub enum ServerMsg {
|
|||||||
TooManyPlayers,
|
TooManyPlayers,
|
||||||
/// Send a popup notification such as "Waypoint Saved"
|
/// Send a popup notification such as "Waypoint Saved"
|
||||||
Notification(Notification),
|
Notification(Notification),
|
||||||
|
SetViewDistance(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[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" }
|
specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git" }
|
||||||
|
|
||||||
tracing = { version = "0.1", default-features = false }
|
tracing = "0.1"
|
||||||
specs = { version = "0.15.1", features = ["shred-derive"] }
|
specs = { version = "0.15.1", features = ["shred-derive"] }
|
||||||
vek = "0.11.0"
|
vek = "0.11.0"
|
||||||
uvth = "3.1.1"
|
uvth = "3.1.1"
|
||||||
|
@ -78,10 +78,12 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler {
|
|||||||
ChatCommand::KillNpcs => handle_kill_npcs,
|
ChatCommand::KillNpcs => handle_kill_npcs,
|
||||||
ChatCommand::Lantern => handle_lantern,
|
ChatCommand::Lantern => handle_lantern,
|
||||||
ChatCommand::Light => handle_light,
|
ChatCommand::Light => handle_light,
|
||||||
|
ChatCommand::Motd => handle_motd,
|
||||||
ChatCommand::Object => handle_object,
|
ChatCommand::Object => handle_object,
|
||||||
ChatCommand::Players => handle_players,
|
ChatCommand::Players => handle_players,
|
||||||
ChatCommand::RemoveLights => handle_remove_lights,
|
ChatCommand::RemoveLights => handle_remove_lights,
|
||||||
ChatCommand::SetLevel => handle_set_level,
|
ChatCommand::SetLevel => handle_set_level,
|
||||||
|
ChatCommand::SetMotd => handle_set_motd,
|
||||||
ChatCommand::Spawn => handle_spawn,
|
ChatCommand::Spawn => handle_spawn,
|
||||||
ChatCommand::Sudo => handle_sudo,
|
ChatCommand::Sudo => handle_sudo,
|
||||||
ChatCommand::Tell => handle_tell,
|
ChatCommand::Tell => handle_tell,
|
||||||
@ -168,6 +170,46 @@ fn handle_give_item(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_motd(
|
||||||
|
server: &mut Server,
|
||||||
|
client: EcsEntity,
|
||||||
|
_target: EcsEntity,
|
||||||
|
_args: String,
|
||||||
|
_action: &ChatCommand,
|
||||||
|
) {
|
||||||
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::broadcast(server.settings().server_description.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_set_motd(
|
||||||
|
server: &mut Server,
|
||||||
|
client: EcsEntity,
|
||||||
|
_target: EcsEntity,
|
||||||
|
args: String,
|
||||||
|
action: &ChatCommand,
|
||||||
|
) {
|
||||||
|
match scan_fmt!(&args, &action.arg_fmt(), String) {
|
||||||
|
Ok(msg) => {
|
||||||
|
server
|
||||||
|
.settings_mut()
|
||||||
|
.edit(|s| s.server_description = msg.clone());
|
||||||
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private(format!("Server description set to \"{}\"", msg)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
server.settings_mut().edit(|s| s.server_description.clear());
|
||||||
|
server.notify_client(
|
||||||
|
client,
|
||||||
|
ServerMsg::private("Removed server description".to_string()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_jump(
|
fn handle_jump(
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
client: EcsEntity,
|
client: EcsEntity,
|
||||||
|
@ -10,10 +10,7 @@ use specs::{Builder, Entity as EcsEntity, WorldExt};
|
|||||||
use vek::{Rgb, Vec3};
|
use vek::{Rgb, Vec3};
|
||||||
|
|
||||||
pub fn handle_initialize_character(server: &mut Server, entity: EcsEntity, character_id: i32) {
|
pub fn handle_initialize_character(server: &mut Server, entity: EcsEntity, character_id: i32) {
|
||||||
let state = &mut server.state;
|
server.state.initialize_character_data(entity, character_id);
|
||||||
let server_settings = &server.server_settings;
|
|
||||||
|
|
||||||
state.initialize_character_data(entity, character_id, server_settings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_loaded_character_data(
|
pub fn handle_loaded_character_data(
|
||||||
@ -21,10 +18,10 @@ pub fn handle_loaded_character_data(
|
|||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
loaded_components: (comp::Body, comp::Stats, comp::Inventory, comp::Loadout),
|
loaded_components: (comp::Body, comp::Stats, comp::Inventory, comp::Loadout),
|
||||||
) {
|
) {
|
||||||
let state = &mut server.state;
|
server
|
||||||
|
.state
|
||||||
state.update_character_data(entity, loaded_components);
|
.update_character_data(entity, loaded_components);
|
||||||
sys::subscription::initialize_region_subscription(state.ecs(), entity);
|
sys::subscription::initialize_region_subscription(server.state.ecs(), entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
|
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![allow(clippy::option_map_unit_fn)]
|
#![allow(clippy::option_map_unit_fn)]
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter, option_zip)]
|
||||||
|
|
||||||
pub mod auth_provider;
|
pub mod auth_provider;
|
||||||
pub mod chunk_generator;
|
pub mod chunk_generator;
|
||||||
@ -43,6 +43,7 @@ use persistence::character::{CharacterLoader, CharacterLoaderResponseType, Chara
|
|||||||
use specs::{join::Join, Builder, Entity as EcsEntity, RunNow, SystemData, WorldExt};
|
use specs::{join::Join, Builder, Entity as EcsEntity, RunNow, SystemData, WorldExt};
|
||||||
use std::{
|
use std::{
|
||||||
i32,
|
i32,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
@ -80,11 +81,8 @@ pub struct Server {
|
|||||||
|
|
||||||
thread_pool: ThreadPool,
|
thread_pool: ThreadPool,
|
||||||
|
|
||||||
server_info: ServerInfo,
|
|
||||||
metrics: ServerMetrics,
|
metrics: ServerMetrics,
|
||||||
tick_metrics: TickMetrics,
|
tick_metrics: TickMetrics,
|
||||||
|
|
||||||
server_settings: ServerSettings,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
@ -93,6 +91,7 @@ impl Server {
|
|||||||
#[allow(clippy::needless_update)] // TODO: Pending review in #587
|
#[allow(clippy::needless_update)] // TODO: Pending review in #587
|
||||||
pub fn new(settings: ServerSettings) -> Result<Self, Error> {
|
pub fn new(settings: ServerSettings) -> Result<Self, Error> {
|
||||||
let mut state = State::default();
|
let mut state = State::default();
|
||||||
|
state.ecs_mut().insert(settings.clone());
|
||||||
state.ecs_mut().insert(EventBus::<ServerEvent>::default());
|
state.ecs_mut().insert(EventBus::<ServerEvent>::default());
|
||||||
state.ecs_mut().insert(AuthProvider::new(
|
state.ecs_mut().insert(AuthProvider::new(
|
||||||
settings.auth_server_address.clone(),
|
settings.auth_server_address.clone(),
|
||||||
@ -238,23 +237,14 @@ impl Server {
|
|||||||
.name("veloren-worker".into())
|
.name("veloren-worker".into())
|
||||||
.build(),
|
.build(),
|
||||||
|
|
||||||
server_info: ServerInfo {
|
|
||||||
name: settings.server_name.clone(),
|
|
||||||
description: settings.server_description.clone(),
|
|
||||||
git_hash: common::util::GIT_HASH.to_string(),
|
|
||||||
git_date: common::util::GIT_DATE.to_string(),
|
|
||||||
auth_provider: settings.auth_server_address.clone(),
|
|
||||||
},
|
|
||||||
metrics,
|
metrics,
|
||||||
tick_metrics,
|
tick_metrics,
|
||||||
server_settings: settings.clone(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Run pending DB migrations (if any)
|
// Run pending DB migrations (if any)
|
||||||
debug!("Running DB migrations...");
|
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");
|
info!(?e, "Migration error");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,11 +257,32 @@ impl Server {
|
|||||||
Ok(this)
|
Ok(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_server_info(&self) -> ServerInfo {
|
||||||
|
let settings = self.state.ecs().fetch::<ServerSettings>();
|
||||||
|
ServerInfo {
|
||||||
|
name: settings.server_name.clone(),
|
||||||
|
description: settings.server_description.clone(),
|
||||||
|
git_hash: common::util::GIT_HASH.to_string(),
|
||||||
|
git_date: common::util::GIT_DATE.to_string(),
|
||||||
|
auth_provider: settings.auth_server_address.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_thread_pool(mut self, thread_pool: ThreadPool) -> Self {
|
pub fn with_thread_pool(mut self, thread_pool: ThreadPool) -> Self {
|
||||||
self.thread_pool = thread_pool;
|
self.thread_pool = thread_pool;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the server's settings
|
||||||
|
pub fn settings(&self) -> impl Deref<Target = ServerSettings> + '_ {
|
||||||
|
self.state.ecs().fetch::<ServerSettings>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference to the server's settings
|
||||||
|
pub fn settings_mut(&mut self) -> impl DerefMut<Target = ServerSettings> + '_ {
|
||||||
|
self.state.ecs_mut().fetch_mut::<ServerSettings>()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a reference to the server's game state.
|
/// Get a reference to the server's game state.
|
||||||
pub fn state(&self) -> &State { &self.state }
|
pub fn state(&self) -> &State { &self.state }
|
||||||
|
|
||||||
@ -575,7 +586,7 @@ impl Server {
|
|||||||
login_msg_sent: false,
|
login_msg_sent: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.server_settings.max_players
|
if self.settings().max_players
|
||||||
<= self.state.ecs().read_storage::<Client>().join().count()
|
<= self.state.ecs().read_storage::<Client>().join().count()
|
||||||
{
|
{
|
||||||
// Note: in this case the client is dropped
|
// Note: in this case the client is dropped
|
||||||
@ -599,7 +610,7 @@ impl Server {
|
|||||||
// Send client their entity
|
// Send client their entity
|
||||||
entity_package: TrackedComps::fetch(&self.state.ecs())
|
entity_package: TrackedComps::fetch(&self.state.ecs())
|
||||||
.create_entity_package(entity, None, None, None),
|
.create_entity_package(entity, None, None, None),
|
||||||
server_info: self.server_info.clone(),
|
server_info: self.get_server_info(),
|
||||||
time_of_day: *self.state.ecs().read_resource(),
|
time_of_day: *self.state.ecs().read_resource(),
|
||||||
world_map: (WORLD_SIZE.map(|e| e as u32), self.map.clone()),
|
world_map: (WORLD_SIZE.map(|e| e as u32), self.map.clone()),
|
||||||
});
|
});
|
||||||
|
@ -24,6 +24,7 @@ pub struct ServerSettings {
|
|||||||
/// uses the value of the file options to decide how to proceed.
|
/// uses the value of the file options to decide how to proceed.
|
||||||
pub map_file: Option<FileOpts>,
|
pub map_file: Option<FileOpts>,
|
||||||
pub persistence_db_dir: String,
|
pub persistence_db_dir: String,
|
||||||
|
pub max_view_distance: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ServerSettings {
|
impl Default for ServerSettings {
|
||||||
@ -61,6 +62,7 @@ impl Default for ServerSettings {
|
|||||||
.collect(),
|
.collect(),
|
||||||
whitelist: Vec::new(),
|
whitelist: Vec::new(),
|
||||||
persistence_db_dir: "saves".to_owned(),
|
persistence_db_dir: "saves".to_owned(),
|
||||||
|
max_view_distance: Some(30),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,9 +97,7 @@ impl ServerSettings {
|
|||||||
|
|
||||||
let s: &str = &ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default())
|
let s: &str = &ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default())
|
||||||
.expect("Failed serialize settings.");
|
.expect("Failed serialize settings.");
|
||||||
config_file
|
config_file.write_all(s.as_bytes())?;
|
||||||
.write_all(s.as_bytes())
|
|
||||||
.expect("Failed to write to config file.");
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,4 +133,11 @@ impl ServerSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_settings_path() -> PathBuf { PathBuf::from(r"server_settings.ron") }
|
fn get_settings_path() -> PathBuf { PathBuf::from(r"server_settings.ron") }
|
||||||
|
|
||||||
|
pub fn edit<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||||
|
let r = f(self);
|
||||||
|
self.save_to_file()
|
||||||
|
.unwrap_or_else(|err| warn!("Failed to save settings: {:?}", err));
|
||||||
|
r
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,12 +38,7 @@ pub trait StateExt {
|
|||||||
projectile: comp::Projectile,
|
projectile: comp::Projectile,
|
||||||
) -> EcsEntityBuilder;
|
) -> EcsEntityBuilder;
|
||||||
/// Insert common/default components for a new character joining the server
|
/// Insert common/default components for a new character joining the server
|
||||||
fn initialize_character_data(
|
fn initialize_character_data(&mut self, entity: EcsEntity, character_id: i32);
|
||||||
&mut self,
|
|
||||||
entity: EcsEntity,
|
|
||||||
character_id: i32,
|
|
||||||
server_settings: &ServerSettings,
|
|
||||||
);
|
|
||||||
/// Update the components associated with the entity's current character.
|
/// Update the components associated with the entity's current character.
|
||||||
/// Performed after loading component data from the database
|
/// Performed after loading component data from the database
|
||||||
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents);
|
fn update_character_data(&mut self, entity: EcsEntity, components: PersistedComponents);
|
||||||
@ -157,12 +152,7 @@ impl StateExt for State {
|
|||||||
.with(comp::Sticky)
|
.with(comp::Sticky)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_character_data(
|
fn initialize_character_data(&mut self, entity: EcsEntity, character_id: i32) {
|
||||||
&mut self,
|
|
||||||
entity: EcsEntity,
|
|
||||||
character_id: i32,
|
|
||||||
server_settings: &ServerSettings,
|
|
||||||
) {
|
|
||||||
let spawn_point = self.ecs().read_resource::<SpawnPoint>().0;
|
let spawn_point = self.ecs().read_resource::<SpawnPoint>().0;
|
||||||
|
|
||||||
self.write_component(entity, comp::Energy::new(1000));
|
self.write_component(entity, comp::Energy::new(1000));
|
||||||
@ -192,7 +182,7 @@ impl StateExt for State {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Give the Admin component to the player if their name exists in admin list
|
// 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
|
&self
|
||||||
.ecs()
|
.ecs()
|
||||||
.read_storage::<comp::Player>()
|
.read_storage::<comp::Player>()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::SysTimer;
|
use super::SysTimer;
|
||||||
use crate::{
|
use crate::{
|
||||||
auth_provider::AuthProvider, client::Client, persistence::character::CharacterLoader,
|
auth_provider::AuthProvider, client::Client, persistence::character::CharacterLoader,
|
||||||
CLIENT_TIMEOUT,
|
ServerSettings, CLIENT_TIMEOUT,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
@ -15,8 +15,8 @@ use common::{
|
|||||||
},
|
},
|
||||||
state::{BlockChange, Time},
|
state::{BlockChange, Time},
|
||||||
sync::Uid,
|
sync::Uid,
|
||||||
terrain::{Block, TerrainGrid},
|
terrain::{Block, TerrainChunkSize, TerrainGrid},
|
||||||
vol::Vox,
|
vol::{RectVolSize, Vox},
|
||||||
};
|
};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use specs::{
|
use specs::{
|
||||||
@ -49,6 +49,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
WriteStorage<'a, Client>,
|
WriteStorage<'a, Client>,
|
||||||
WriteStorage<'a, Controller>,
|
WriteStorage<'a, Controller>,
|
||||||
WriteStorage<'a, SpeechBubble>,
|
WriteStorage<'a, SpeechBubble>,
|
||||||
|
Read<'a, ServerSettings>,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[allow(clippy::match_ref_pats)] // TODO: Pending review in #587
|
#[allow(clippy::match_ref_pats)] // TODO: Pending review in #587
|
||||||
@ -77,6 +78,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
mut clients,
|
mut clients,
|
||||||
mut controllers,
|
mut controllers,
|
||||||
mut speech_bubbles,
|
mut speech_bubbles,
|
||||||
|
settings,
|
||||||
): Self::SystemData,
|
): Self::SystemData,
|
||||||
) {
|
) {
|
||||||
timer.start();
|
timer.start();
|
||||||
@ -156,7 +158,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
Ok((username, uuid)) => (username, uuid),
|
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() {
|
if !player.is_valid() {
|
||||||
// Invalid player
|
// Invalid player
|
||||||
@ -184,12 +188,40 @@ impl<'a> System<'a> for Sys {
|
|||||||
_ => client.error_state(RequestStateError::Impossible),
|
_ => client.error_state(RequestStateError::Impossible),
|
||||||
}
|
}
|
||||||
//client.allow_state(ClientState::Registered);
|
//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 {
|
ClientMsg::SetViewDistance(view_distance) => match client.client_state {
|
||||||
ClientState::Character { .. } => {
|
ClientState::Character { .. } => {
|
||||||
players
|
if settings
|
||||||
.get_mut(entity)
|
.max_view_distance
|
||||||
.map(|player| player.view_distance = Some(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),
|
||||||
|
));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
},
|
},
|
||||||
@ -214,6 +246,13 @@ impl<'a> System<'a> for Sys {
|
|||||||
character_id,
|
character_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Give the player a welcome message
|
||||||
|
if settings.server_description.len() > 0 {
|
||||||
|
client.notify(ServerMsg::broadcast(
|
||||||
|
settings.server_description.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// Only send login message if it wasn't already
|
// Only send login message if it wasn't already
|
||||||
// sent previously
|
// sent previously
|
||||||
if !client.login_msg_sent {
|
if !client.login_msg_sent {
|
||||||
@ -323,14 +362,30 @@ impl<'a> System<'a> for Sys {
|
|||||||
client.error_state(RequestStateError::Impossible);
|
client.error_state(RequestStateError::Impossible);
|
||||||
},
|
},
|
||||||
ClientState::Spectator | ClientState::Character => {
|
ClientState::Spectator | ClientState::Character => {
|
||||||
match terrain.get_key(key) {
|
let in_vd = if let (Some(view_distance), Some(pos)) = (
|
||||||
Some(chunk) => {
|
players.get(entity).and_then(|p| p.view_distance),
|
||||||
client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
positions.get(entity),
|
||||||
key,
|
) {
|
||||||
chunk: Ok(Box::new(chunk.clone())),
|
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),
|
||||||
None => server_emitter.emit(ServerEvent::ChunkRequest(entity, key)),
|
) < (view_distance as f64 + 1.5)
|
||||||
|
* 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))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ClientState::Pending => {},
|
ClientState::Pending => {},
|
||||||
|
@ -75,7 +75,7 @@ impl SessionState {
|
|||||||
|
|
||||||
impl SessionState {
|
impl SessionState {
|
||||||
/// Tick the session (and the client attached to it).
|
/// 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);
|
self.inputs.tick(dt);
|
||||||
|
|
||||||
for event in self.client.borrow_mut().tick(
|
for event in self.client.borrow_mut().tick(
|
||||||
@ -107,6 +107,10 @@ impl SessionState {
|
|||||||
self.hud
|
self.hud
|
||||||
.new_message(client::Event::Notification(Notification::WaypointSaved));
|
.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()
|
|| !global_state.singleplayer.as_ref().unwrap().is_paused()
|
||||||
{
|
{
|
||||||
// Perform an in-game tick.
|
// 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::Continue) => {}, // Do nothing
|
||||||
Ok(TickAction::Disconnect) => return PlayStateResult::Pop, // Go to main menu
|
Ok(TickAction::Disconnect) => return PlayStateResult::Pop, // Go to main menu
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user