mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Move server-cli commands to separate file, tracy profiling par_join improvements, misc improvements
- remove overwritten logging setting in server-cli - add server-cli command to load a random area for testing without a client - make admin add/remove commands modify ingame players instead of needing to reconnect - add spans to par_join jobs - added test command that loads up an area of the world - add tracy-world-server alias - set debug directives to info for logging
This commit is contained in:
parent
4022937da7
commit
8d0b776f18
@ -8,6 +8,7 @@ csv-export = "run --manifest-path common/Cargo.toml --features=bin_csv --bin csv
|
||||
csv-import = "run --manifest-path common/Cargo.toml --features=bin_csv --bin csv_import"
|
||||
test-server = "-Zpackage-features run --bin veloren-server-cli --no-default-features -- -b"
|
||||
tracy-server = "-Zunstable-options -Zpackage-features run --bin veloren-server-cli --no-default-features --features tracy,simd --profile no_overflow"
|
||||
tracy-world-server = "-Zunstable-options -Zpackage-features run --bin veloren-server-cli --features tracy,simd --profile no_overflow -- -bi"
|
||||
test-voxygen = "-Zpackage-features run --bin veloren-voxygen --no-default-features --features gl,simd"
|
||||
tracy-voxygen = "-Zunstable-options -Zpackage-features run --bin veloren-voxygen --no-default-features --features tracy,gl,simd --profile no_overflow"
|
||||
server = "run --bin veloren-server-cli"
|
||||
|
@ -41,6 +41,25 @@ macro_rules! span {
|
||||
};
|
||||
}
|
||||
|
||||
/// Like the span macro but only used when profiling and not in regular tracing
|
||||
/// operations
|
||||
#[macro_export]
|
||||
macro_rules! prof_span {
|
||||
($guard_name:tt, $name:expr) => {
|
||||
#[cfg(feature = "tracy")]
|
||||
let $guard_name = $crate::tracy_client::Span::new(
|
||||
$name,
|
||||
"",
|
||||
module_path!(),
|
||||
line!(),
|
||||
// No callstack since this has significant overhead
|
||||
0,
|
||||
);
|
||||
#[cfg(not(feature = "tracy"))]
|
||||
let $guard_name = ();
|
||||
};
|
||||
}
|
||||
|
||||
/// There's no guard, but really this is actually the guard
|
||||
pub struct GuardlessSpan {
|
||||
span: tracing::Span,
|
||||
|
@ -253,7 +253,10 @@ where
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
common_base::span!(_guard, "run", &format!("{}::Sys::run", T::NAME));
|
||||
self.cpu_stats.reset();
|
||||
{
|
||||
common_base::span!(_guard, "run inner", &format!("{}::Sys::run inner", T::NAME));
|
||||
T::run(self, data.0);
|
||||
}
|
||||
self.cpu_stats.end();
|
||||
data.1
|
||||
.stats
|
||||
|
@ -18,6 +18,11 @@
|
||||
trait_alias,
|
||||
type_alias_impl_trait
|
||||
)]
|
||||
|
||||
/// Re-exported crates
|
||||
pub use uuid;
|
||||
|
||||
// modules
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod assets;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod astar;
|
||||
|
@ -49,6 +49,27 @@ impl RectVolSize for TerrainChunkSize {
|
||||
};
|
||||
}
|
||||
|
||||
impl TerrainChunkSize {
|
||||
#[inline(always)]
|
||||
/// Convert dimensions in terms of chunks into dimensions in terms of blocks
|
||||
/// ```
|
||||
/// assert_eq!(TerrainChunkSize::blocks(Vec2::new(3, 2)), Vec2::new(96, 64));
|
||||
/// ```
|
||||
pub fn blocks(chunks: Vec2<u32>) -> Vec2<u32> { chunks * Self::RECT_SIZE }
|
||||
|
||||
/// Calculate the world position (i.e. in blocks) at the center of this
|
||||
/// chunk
|
||||
/// ```
|
||||
/// assert_eq!(
|
||||
/// TerrainChunkSize::center_wpos(Vec2::new(0, 2)),
|
||||
/// Vec2::new(16, 80)
|
||||
/// );
|
||||
/// ```
|
||||
pub fn center_wpos(chunk_pos: Vec2<i32>) -> Vec2<i32> {
|
||||
chunk_pos * Self::RECT_SIZE.as_::<i32>() + Self::RECT_SIZE.as_::<i32>() / 2
|
||||
}
|
||||
}
|
||||
|
||||
// TerrainChunkMeta
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
@ -10,7 +10,7 @@ use common::{
|
||||
uid::Uid,
|
||||
vol::ReadVol,
|
||||
};
|
||||
use common_base::span;
|
||||
use common_base::{prof_span, span};
|
||||
use common_ecs::{Job, Origin, ParMode, Phase, PhysicsMetrics, System};
|
||||
use rayon::iter::ParallelIterator;
|
||||
use specs::{Entities, Join, ParJoin, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
|
||||
@ -232,9 +232,12 @@ impl<'a> System<'a> for Sys {
|
||||
sticky.is_none() || (physics.on_wall.is_none() && !physics.on_ground)
|
||||
})
|
||||
.map(|(e, p, v, vd, m, c, _, _, ph, pr, c_s)| (e, p, v, vd, m, c, ph, pr, c_s))
|
||||
.fold(
|
||||
PhysicsMetrics::default,
|
||||
|mut metrics,
|
||||
.map_init(
|
||||
|| {
|
||||
prof_span!(guard, "physics e<>e rayon job");
|
||||
guard
|
||||
},
|
||||
|_guard,
|
||||
(
|
||||
entity,
|
||||
pos,
|
||||
@ -256,6 +259,9 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
let mut vel_delta = Vec3::zero();
|
||||
|
||||
let mut entity_entity_collision_checks = 0;
|
||||
let mut entity_entity_collisions = 0;
|
||||
|
||||
for (
|
||||
entity_other,
|
||||
other,
|
||||
@ -307,7 +313,7 @@ impl<'a> System<'a> for Sys {
|
||||
continue;
|
||||
}
|
||||
|
||||
metrics.entity_entity_collision_checks += 1;
|
||||
entity_entity_collision_checks += 1;
|
||||
|
||||
const MIN_COLLISION_DIST: f32 = 0.3;
|
||||
let increments = ((previous_cache.velocity_dt
|
||||
@ -334,7 +340,7 @@ impl<'a> System<'a> for Sys {
|
||||
{
|
||||
if !collided {
|
||||
physics.touch_entities.push(*other);
|
||||
metrics.entity_entity_collisions += 1;
|
||||
entity_entity_collisions += 1;
|
||||
}
|
||||
|
||||
// Don't apply repulsive force to projectiles
|
||||
@ -353,7 +359,12 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
// Change velocity
|
||||
vel.0 += vel_delta * dt.0;
|
||||
metrics
|
||||
|
||||
// Metrics
|
||||
PhysicsMetrics {
|
||||
entity_entity_collision_checks,
|
||||
entity_entity_collisions,
|
||||
}
|
||||
},
|
||||
)
|
||||
.reduce(PhysicsMetrics::default, |old, new| PhysicsMetrics {
|
||||
@ -380,13 +391,19 @@ impl<'a> System<'a> for Sys {
|
||||
!&mountings,
|
||||
)
|
||||
.par_join()
|
||||
.fold(Vec::new, |
|
||||
mut land_on_grounds,
|
||||
.map_init(
|
||||
|| {
|
||||
prof_span!(guard, "physics e<>t rayon job");
|
||||
guard
|
||||
},
|
||||
|_guard,
|
||||
(entity, _scale, sticky, collider, mut pos, mut vel, _ori, mut physics_state, _),
|
||||
| {
|
||||
let mut landed_on_ground = None;
|
||||
|
||||
if sticky.is_some() && physics_state.on_surface().is_some() {
|
||||
vel.0 = Vec3::zero();
|
||||
return land_on_grounds;
|
||||
return landed_on_ground;
|
||||
}
|
||||
|
||||
// TODO: Use this
|
||||
@ -593,7 +610,7 @@ impl<'a> System<'a> for Sys {
|
||||
on_ground = true;
|
||||
|
||||
if !was_on_ground {
|
||||
land_on_grounds.push((entity, *vel));
|
||||
landed_on_ground = Some((entity, *vel));
|
||||
}
|
||||
} else if resolve_dir.z < 0.0 && vel.0.z >= 0.0 {
|
||||
on_ceiling = true;
|
||||
@ -770,7 +787,12 @@ impl<'a> System<'a> for Sys {
|
||||
},
|
||||
}
|
||||
|
||||
land_on_grounds
|
||||
landed_on_ground
|
||||
}).fold(Vec::new, |mut lands_on_grounds, landed_on_ground| {
|
||||
if let Some(land_on_ground) = landed_on_ground {
|
||||
lands_on_grounds.push(land_on_ground);
|
||||
}
|
||||
lands_on_grounds
|
||||
}).reduce(Vec::new, |mut land_on_grounds_a, mut land_on_grounds_b| {
|
||||
land_on_grounds_a.append(&mut land_on_grounds_b);
|
||||
land_on_grounds_a
|
||||
|
@ -16,12 +16,12 @@ pub fn admin_subcommand(
|
||||
match sub_m.subcommand() {
|
||||
("add", Some(sub_m)) => {
|
||||
if let Some(username) = sub_m.value_of("username") {
|
||||
server::add_admin(username, &login_provider, editable_settings, data_dir)
|
||||
server::add_admin(username, &login_provider, editable_settings, data_dir);
|
||||
}
|
||||
},
|
||||
("remove", Some(sub_m)) => {
|
||||
if let Some(username) = sub_m.value_of("username") {
|
||||
server::remove_admin(username, &login_provider, editable_settings, data_dir)
|
||||
server::remove_admin(username, &login_provider, editable_settings, data_dir);
|
||||
}
|
||||
},
|
||||
// TODO: can clap enforce this?
|
||||
|
140
server-cli/src/cmd.rs
Normal file
140
server-cli/src/cmd.rs
Normal file
@ -0,0 +1,140 @@
|
||||
use core::time::Duration;
|
||||
use std::sync::mpsc::Sender;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message {
|
||||
AbortShutdown,
|
||||
Shutdown { grace_period: Duration },
|
||||
Quit,
|
||||
AddAdmin(String),
|
||||
RemoveAdmin(String),
|
||||
LoadArea(u32),
|
||||
}
|
||||
|
||||
struct Command<'a> {
|
||||
name: &'a str,
|
||||
description: &'a str,
|
||||
// Whether or not the command splits the arguments on whitespace
|
||||
split_spaces: bool,
|
||||
args: usize,
|
||||
cmd: fn(Vec<String>, &mut Sender<Message>),
|
||||
}
|
||||
|
||||
// TODO: maybe we could be using clap here?
|
||||
const COMMANDS: [Command; 6] = [
|
||||
Command {
|
||||
name: "quit",
|
||||
description: "Closes the server",
|
||||
split_spaces: true,
|
||||
args: 0,
|
||||
cmd: |_, sender| sender.send(Message::Quit).unwrap(),
|
||||
},
|
||||
Command {
|
||||
name: "shutdown",
|
||||
description: "Initiates a graceful shutdown of the server, waiting the specified number \
|
||||
of seconds before shutting down",
|
||||
split_spaces: true,
|
||||
args: 1,
|
||||
cmd: |args, sender| {
|
||||
if let Ok(grace_period) = args.first().unwrap().parse::<u64>() {
|
||||
sender
|
||||
.send(Message::Shutdown {
|
||||
grace_period: Duration::from_secs(grace_period),
|
||||
})
|
||||
.unwrap()
|
||||
} else {
|
||||
error!("Grace period must an integer")
|
||||
}
|
||||
},
|
||||
},
|
||||
Command {
|
||||
name: "loadarea",
|
||||
description: "Loads up the chunks in a random area and adds a entity that mimics a player \
|
||||
to keep them from despawning",
|
||||
split_spaces: true,
|
||||
args: 1,
|
||||
cmd: |args, sender| {
|
||||
if let Ok(view_distance) = args.first().unwrap().parse::<u32>() {
|
||||
sender.send(Message::LoadArea(view_distance)).unwrap();
|
||||
} else {
|
||||
error!("View distance must be an integer");
|
||||
}
|
||||
},
|
||||
},
|
||||
Command {
|
||||
name: "abortshutdown",
|
||||
description: "Aborts a shutdown if one is in progress",
|
||||
split_spaces: false,
|
||||
args: 0,
|
||||
cmd: |_, sender| sender.send(Message::AbortShutdown).unwrap(),
|
||||
},
|
||||
Command {
|
||||
name: "admin",
|
||||
description: "Add or remove an admin via \'admin add/remove <username>\'",
|
||||
split_spaces: true,
|
||||
args: 2,
|
||||
cmd: |args, sender| match args.get(..2) {
|
||||
Some([op, username]) if op == "add" => {
|
||||
sender.send(Message::AddAdmin(username.clone())).unwrap()
|
||||
},
|
||||
Some([op, username]) if op == "remove" => {
|
||||
sender.send(Message::RemoveAdmin(username.clone())).unwrap()
|
||||
},
|
||||
Some(_) => error!("First arg must be add or remove"),
|
||||
_ => error!("Not enough args, should be unreachable"),
|
||||
},
|
||||
},
|
||||
Command {
|
||||
name: "help",
|
||||
description: "List all command available",
|
||||
split_spaces: true,
|
||||
args: 0,
|
||||
cmd: |_, _| {
|
||||
info!("===== Help =====");
|
||||
for command in COMMANDS.iter() {
|
||||
info!("{} - {}", command.name, command.description)
|
||||
}
|
||||
info!("================");
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
pub fn parse_command(input: &str, msg_s: &mut Sender<Message>) {
|
||||
let mut args = input.split_whitespace();
|
||||
|
||||
if let Some(cmd_name) = args.next() {
|
||||
if let Some(cmd) = COMMANDS.iter().find(|cmd| cmd.name == cmd_name) {
|
||||
let args = args.collect::<Vec<_>>();
|
||||
|
||||
let (arg_len, args) = if cmd.split_spaces {
|
||||
(
|
||||
args.len(),
|
||||
args.into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
)
|
||||
} else {
|
||||
(0, vec![args.into_iter().collect::<String>()])
|
||||
};
|
||||
|
||||
use core::cmp::Ordering;
|
||||
match arg_len.cmp(&cmd.args) {
|
||||
Ordering::Less => error!("{} takes {} arguments", cmd_name, cmd.args),
|
||||
Ordering::Greater => {
|
||||
warn!("{} only takes {} arguments", cmd_name, cmd.args);
|
||||
let cmd = cmd.cmd;
|
||||
|
||||
cmd(args, msg_s)
|
||||
},
|
||||
Ordering::Equal => {
|
||||
let cmd = cmd.cmd;
|
||||
|
||||
cmd(args, msg_s)
|
||||
},
|
||||
}
|
||||
} else {
|
||||
error!("{} not found", cmd_name);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
use crate::tuilog::TuiLog;
|
||||
use termcolor::{ColorChoice, StandardStream};
|
||||
use tracing::Level;
|
||||
use tracing_subscriber::{filter::LevelFilter, EnvFilter, FmtSubscriber};
|
||||
#[cfg(feature = "tracy")]
|
||||
use tracing_subscriber::{layer::SubscriberExt, prelude::*};
|
||||
@ -19,10 +18,10 @@ pub fn init(basic: bool) {
|
||||
.add_directive("hyper=info".parse().unwrap())
|
||||
.add_directive("prometheus_hyper=info".parse().unwrap())
|
||||
.add_directive("mio::pool=info".parse().unwrap())
|
||||
.add_directive("mio::sys::windows=debug".parse().unwrap())
|
||||
.add_directive("mio::sys::windows=info".parse().unwrap())
|
||||
.add_directive("h2=info".parse().unwrap())
|
||||
.add_directive("tokio_util=info".parse().unwrap())
|
||||
.add_directive("rustls=debug".parse().unwrap())
|
||||
.add_directive("rustls=info".parse().unwrap())
|
||||
.add_directive("veloren_network_protocol=info".parse().unwrap())
|
||||
.add_directive(
|
||||
"veloren_server::persistence::character=info"
|
||||
@ -32,7 +31,6 @@ pub fn init(basic: bool) {
|
||||
.add_directive(LevelFilter::INFO.into())
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "tracy"))]
|
||||
let filter = match std::env::var_os(RUST_LOG_ENV).map(|s| s.into_string()) {
|
||||
Some(Ok(env)) => {
|
||||
let mut filter = base_exceptions(EnvFilter::new(""));
|
||||
@ -49,6 +47,7 @@ pub fn init(basic: bool) {
|
||||
|
||||
#[cfg(feature = "tracy")]
|
||||
tracing_subscriber::registry()
|
||||
.with(filter)
|
||||
.with(tracing_tracy::TracyLayer::new().with_stackdepth(0))
|
||||
.init();
|
||||
|
||||
@ -56,9 +55,7 @@ pub fn init(basic: bool) {
|
||||
// TODO: when tracing gets per Layer filters re-enable this when the tracy feature is being
|
||||
// used (and do the same in voxygen)
|
||||
{
|
||||
let subscriber = FmtSubscriber::builder()
|
||||
.with_max_level(Level::ERROR)
|
||||
.with_env_filter(filter);
|
||||
let subscriber = FmtSubscriber::builder().with_env_filter(filter);
|
||||
|
||||
if basic {
|
||||
subscriber
|
||||
|
@ -3,16 +3,16 @@
|
||||
#![feature(bool_to_option)]
|
||||
|
||||
mod admin;
|
||||
/// `server-cli` interface commands not to be confused with the commands sent
|
||||
/// from the client to the server
|
||||
mod cmd;
|
||||
mod logging;
|
||||
mod settings;
|
||||
mod shutdown_coordinator;
|
||||
mod tui_runner;
|
||||
mod tuilog;
|
||||
|
||||
use crate::{
|
||||
shutdown_coordinator::ShutdownCoordinator,
|
||||
tui_runner::{Message, Tui},
|
||||
};
|
||||
use crate::{cmd::Message, shutdown_coordinator::ShutdownCoordinator, tui_runner::Tui};
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use common::clock::Clock;
|
||||
use common_base::span;
|
||||
@ -201,6 +201,9 @@ fn main() -> io::Result<()> {
|
||||
Message::RemoveAdmin(username) => {
|
||||
server.remove_admin(&username);
|
||||
},
|
||||
Message::LoadArea(view_distance) => {
|
||||
server.create_centered_persister(view_distance);
|
||||
},
|
||||
},
|
||||
Err(mpsc::TryRecvError::Empty) | Err(mpsc::TryRecvError::Disconnected) => {},
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::logging::LOG;
|
||||
use crate::{cmd, logging::LOG, Message};
|
||||
use crossterm::{
|
||||
event::{DisableMouseCapture, EnableMouseCapture},
|
||||
execute,
|
||||
@ -12,7 +12,7 @@ use std::{
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tracing::{debug, error, warn};
|
||||
use tui::{
|
||||
backend::CrosstermBackend,
|
||||
layout::Rect,
|
||||
@ -21,89 +21,6 @@ use tui::{
|
||||
Terminal,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message {
|
||||
AbortShutdown,
|
||||
Shutdown { grace_period: Duration },
|
||||
Quit,
|
||||
AddAdmin(String),
|
||||
RemoveAdmin(String),
|
||||
}
|
||||
|
||||
pub struct Command<'a> {
|
||||
pub name: &'a str,
|
||||
pub description: &'a str,
|
||||
// Whether or not the command splits the arguments on whitespace
|
||||
pub split_spaces: bool,
|
||||
pub args: usize,
|
||||
pub cmd: fn(Vec<String>, &mut mpsc::Sender<Message>),
|
||||
}
|
||||
|
||||
// TODO: mabye we could be using clap here?
|
||||
pub const COMMANDS: [Command; 5] = [
|
||||
Command {
|
||||
name: "quit",
|
||||
description: "Closes the server",
|
||||
split_spaces: true,
|
||||
args: 0,
|
||||
cmd: |_, sender| sender.send(Message::Quit).unwrap(),
|
||||
},
|
||||
Command {
|
||||
name: "shutdown",
|
||||
description: "Initiates a graceful shutdown of the server, waiting the specified number \
|
||||
of seconds before shutting down",
|
||||
split_spaces: true,
|
||||
args: 1,
|
||||
cmd: |args, sender| {
|
||||
if let Ok(grace_period) = args.first().unwrap().parse::<u64>() {
|
||||
sender
|
||||
.send(Message::Shutdown {
|
||||
grace_period: Duration::from_secs(grace_period),
|
||||
})
|
||||
.unwrap()
|
||||
} else {
|
||||
error!("Grace period must an integer")
|
||||
}
|
||||
},
|
||||
},
|
||||
Command {
|
||||
name: "abortshutdown",
|
||||
description: "Aborts a shutdown if one is in progress",
|
||||
split_spaces: false,
|
||||
args: 0,
|
||||
cmd: |_, sender| sender.send(Message::AbortShutdown).unwrap(),
|
||||
},
|
||||
Command {
|
||||
name: "admin",
|
||||
description: "Add or remove an admin via \'admin add/remove <username>\'",
|
||||
split_spaces: true,
|
||||
args: 2,
|
||||
cmd: |args, sender| match args.get(..2) {
|
||||
Some([op, username]) if op == "add" => {
|
||||
sender.send(Message::AddAdmin(username.clone())).unwrap()
|
||||
},
|
||||
Some([op, username]) if op == "remove" => {
|
||||
sender.send(Message::RemoveAdmin(username.clone())).unwrap()
|
||||
},
|
||||
Some(_) => error!("First arg must be add or remove"),
|
||||
_ => error!("Not enough args, should be unreachable"),
|
||||
},
|
||||
},
|
||||
Command {
|
||||
name: "help",
|
||||
description: "List all command available",
|
||||
split_spaces: true,
|
||||
args: 0,
|
||||
cmd: |_, _| {
|
||||
info!("===== Help =====");
|
||||
for command in COMMANDS.iter() {
|
||||
info!("{} - {}", command.name, command.description)
|
||||
}
|
||||
info!("================");
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
pub struct Tui {
|
||||
pub msg_r: mpsc::Receiver<Message>,
|
||||
background: Option<std::thread::JoinHandle<()>>,
|
||||
@ -129,7 +46,7 @@ impl Tui {
|
||||
},
|
||||
KeyCode::Enter => {
|
||||
debug!(?input, "tui mode: command entered");
|
||||
parse_command(input, msg_s);
|
||||
cmd::parse_command(input, msg_s);
|
||||
|
||||
*input = String::new();
|
||||
},
|
||||
@ -163,7 +80,7 @@ impl Tui {
|
||||
},
|
||||
Ok(_) => {
|
||||
debug!(?line, "basic mode: command entered");
|
||||
parse_command(&line, &mut msg_s);
|
||||
crate::cmd::parse_command(&line, &mut msg_s);
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -263,41 +180,3 @@ impl Drop for Tui {
|
||||
Tui::shutdown(self.basic);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_command(input: &str, msg_s: &mut mpsc::Sender<Message>) {
|
||||
let mut args = input.split_whitespace();
|
||||
|
||||
if let Some(cmd_name) = args.next() {
|
||||
if let Some(cmd) = COMMANDS.iter().find(|cmd| cmd.name == cmd_name) {
|
||||
let args = args.collect::<Vec<_>>();
|
||||
|
||||
let (arg_len, args) = if cmd.split_spaces {
|
||||
(
|
||||
args.len(),
|
||||
args.into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
)
|
||||
} else {
|
||||
(0, vec![args.into_iter().collect::<String>()])
|
||||
};
|
||||
|
||||
match arg_len.cmp(&cmd.args) {
|
||||
std::cmp::Ordering::Less => error!("{} takes {} arguments", cmd_name, cmd.args),
|
||||
std::cmp::Ordering::Greater => {
|
||||
warn!("{} only takes {} arguments", cmd_name, cmd.args);
|
||||
let cmd = cmd.cmd;
|
||||
|
||||
cmd(args, msg_s)
|
||||
},
|
||||
std::cmp::Ordering::Equal => {
|
||||
let cmd = cmd.cmd;
|
||||
|
||||
cmd(args, msg_s)
|
||||
},
|
||||
}
|
||||
} else {
|
||||
error!("{} not found", cmd_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -305,14 +305,10 @@ impl Server {
|
||||
.min_by_key(|site_pos| site_pos.distance_squared(center_chunk))
|
||||
.unwrap_or(center_chunk);
|
||||
|
||||
// calculate the absolute position of the chunk in the world
|
||||
// (we could add TerrainChunkSize::RECT_SIZE / 2 here, to spawn in the middle of
|
||||
// the chunk)
|
||||
let spawn_wpos = spawn_chunk.map2(TerrainChunkSize::RECT_SIZE, |e, sz| {
|
||||
e as i32 * sz as i32 + sz as i32 / 2
|
||||
});
|
||||
// Calculate the middle of the chunk in the world
|
||||
let spawn_wpos = TerrainChunkSize::center_wpos(spawn_chunk);
|
||||
|
||||
// unwrapping because generate_chunk only returns err when should_continue evals
|
||||
// Unwrapping because generate_chunk only returns err when should_continue evals
|
||||
// to true
|
||||
let (tc, _cs) = world.generate_chunk(index, spawn_chunk, || false).unwrap();
|
||||
let min_z = tc.get_min_z();
|
||||
@ -345,7 +341,7 @@ impl Server {
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
let spawn_point = Vec3::new(0.0, 0.0, 256.0);
|
||||
|
||||
// set the spawn point we calculated above
|
||||
// Set the spawn point we calculated above
|
||||
state.ecs_mut().insert(SpawnPoint(spawn_point));
|
||||
|
||||
// Insert the world into the ECS (todo: Maybe not an Arc?)
|
||||
@ -931,30 +927,63 @@ impl Server {
|
||||
self.state.ecs().read_storage::<Client>().join().count() as i64
|
||||
}
|
||||
|
||||
// TODO: add Admin comp if ingame
|
||||
pub fn add_admin(&self, username: &str) {
|
||||
let mut editable_settings = self.editable_settings_mut();
|
||||
let login_provider = self.state.ecs().fetch::<LoginProvider>();
|
||||
let data_dir = self.data_dir();
|
||||
add_admin(
|
||||
if let Some(entity) = add_admin(
|
||||
username,
|
||||
&login_provider,
|
||||
&mut editable_settings,
|
||||
&data_dir.path,
|
||||
);
|
||||
).and_then(|uuid| {
|
||||
let state = &self.state;
|
||||
(&state.ecs().entities(), &state.read_storage::<comp::Player>())
|
||||
.join()
|
||||
.find(|(_, player)| player.uuid() == uuid)
|
||||
.map(|(e, _)| e)
|
||||
}) {
|
||||
// Add admin component if the player is ingame
|
||||
let _ = self.state.ecs().write_storage().insert(entity, comp::Admin);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: remove Admin comp if ingame
|
||||
pub fn remove_admin(&self, username: &str) {
|
||||
let mut editable_settings = self.editable_settings_mut();
|
||||
let login_provider = self.state.ecs().fetch::<LoginProvider>();
|
||||
let data_dir = self.data_dir();
|
||||
remove_admin(
|
||||
if let Some(entity) = remove_admin(
|
||||
username,
|
||||
&login_provider,
|
||||
&mut editable_settings,
|
||||
&data_dir.path,
|
||||
);
|
||||
).and_then(|uuid| {
|
||||
let state = &self.state;
|
||||
(&state.ecs().entities(), &state.read_storage::<comp::Player>())
|
||||
.join()
|
||||
.find(|(_, player)| player.uuid() == uuid)
|
||||
.map(|(e, _)| e)
|
||||
}) {
|
||||
// Remove admin component if the player is ingame
|
||||
let _ = self.state.ecs().write_storage::<comp::Admin>().remove(entity);
|
||||
};
|
||||
}
|
||||
|
||||
/// Useful for testing without a client
|
||||
/// view_distance: distance in chunks that are persisted, this acts like the player view
|
||||
/// distance so it is actually a bit farther due to a buffer zone
|
||||
pub fn create_centered_persister(&mut self, view_distance: u32) {
|
||||
let world_dims_chunks = self.world.sim().get_size();
|
||||
let world_dims_blocks = TerrainChunkSize::blocks(world_dims_chunks);
|
||||
// NOTE: origin is in the corner of the map
|
||||
// TODO: extend this function to have picking a random position or specifiying a position
|
||||
// as options
|
||||
//let mut rng = rand::thread_rng();
|
||||
// // Pick a random position but not to close to the edge
|
||||
// let rand_pos = world_dims_blocks.map(|e| e as i32).map(|e| e / 2 + rng.gen_range(-e/2..e/2 + 1));
|
||||
let pos = comp::Pos(Vec3::from(world_dims_blocks.map(|e| e as f32 / 2.0)));
|
||||
self.state.create_persister(pos, view_distance, &self.world, &self.index, &self.runtime).build();
|
||||
}
|
||||
}
|
||||
|
||||
@ -966,35 +995,42 @@ impl Drop for Server {
|
||||
}
|
||||
}
|
||||
|
||||
/// If successful returns the Some(uuid) of the added admin
|
||||
pub fn add_admin(
|
||||
username: &str,
|
||||
login_provider: &LoginProvider,
|
||||
editable_settings: &mut EditableSettings,
|
||||
data_dir: &std::path::Path,
|
||||
) {
|
||||
) -> Option<common::uuid::Uuid> {
|
||||
use crate::settings::EditableSetting;
|
||||
match login_provider.username_to_uuid(username) {
|
||||
Ok(uuid) => editable_settings.admins.edit(data_dir, |admins| {
|
||||
if admins.insert(uuid) {
|
||||
info!("Successfully added {} ({}) as an admin!", username, uuid);
|
||||
Some(uuid)
|
||||
} else {
|
||||
info!("{} ({}) is already an admin!", username, uuid);
|
||||
None
|
||||
}
|
||||
}),
|
||||
Err(err) => error!(
|
||||
Err(err) => {
|
||||
error!(
|
||||
?err,
|
||||
"Could not find uuid for this name either the user does not exist or there was an \
|
||||
error communicating with the auth server."
|
||||
),
|
||||
);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// If successful returns the Some(uuid) of the removed admin
|
||||
pub fn remove_admin(
|
||||
username: &str,
|
||||
login_provider: &LoginProvider,
|
||||
editable_settings: &mut EditableSettings,
|
||||
data_dir: &std::path::Path,
|
||||
) {
|
||||
) -> Option<common::uuid::Uuid> {
|
||||
use crate::settings::EditableSetting;
|
||||
match login_provider.username_to_uuid(username) {
|
||||
Ok(uuid) => editable_settings.admins.edit(data_dir, |admins| {
|
||||
@ -1003,14 +1039,19 @@ pub fn remove_admin(
|
||||
"Successfully removed {} ({}) from the admins",
|
||||
username, uuid
|
||||
);
|
||||
Some(uuid)
|
||||
} else {
|
||||
info!("{} ({}) is not an admin!", username, uuid);
|
||||
None
|
||||
}
|
||||
}),
|
||||
Err(err) => error!(
|
||||
Err(err) => {
|
||||
error!(
|
||||
?err,
|
||||
"Could not find uuid for this name either the user does not exist or there was an \
|
||||
error communicating with the auth server."
|
||||
),
|
||||
);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,18 @@ pub trait StateExt {
|
||||
pos: comp::Pos,
|
||||
ori: comp::Ori,
|
||||
) -> EcsEntityBuilder;
|
||||
// NOTE: currently only used for testing
|
||||
/// Queues chunk generation in the view distance of the persister, this
|
||||
/// entity must be built before those chunks are received (the builder
|
||||
/// borrows the ecs world so that is kind of impossible in practice)
|
||||
fn create_persister(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
view_distance: u32,
|
||||
world: &std::sync::Arc<world::World>,
|
||||
index: &world::IndexOwned,
|
||||
runtime: &tokio::runtime::Runtime,
|
||||
) -> EcsEntityBuilder;
|
||||
/// Insert common/default components for a new character joining the server
|
||||
fn initialize_character_data(&mut self, entity: EcsEntity, character_id: CharacterId);
|
||||
/// Update the components associated with the entity's current character.
|
||||
@ -257,6 +269,50 @@ impl StateExt for State {
|
||||
})
|
||||
}
|
||||
|
||||
// NOTE: currently only used for testing
|
||||
/// Queues chunk generation in the view distance of the persister, this
|
||||
/// entity must be built before those chunks are received (the builder
|
||||
/// borrows the ecs world so that is kind of impossible in practice)
|
||||
fn create_persister(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
view_distance: u32,
|
||||
world: &std::sync::Arc<world::World>,
|
||||
index: &world::IndexOwned,
|
||||
runtime: &tokio::runtime::Runtime,
|
||||
) -> EcsEntityBuilder {
|
||||
use common::{terrain::TerrainChunkSize, vol::RectVolSize};
|
||||
use std::sync::Arc;
|
||||
// Request chunks
|
||||
{
|
||||
let mut chunk_generator = self
|
||||
.ecs()
|
||||
.write_resource::<crate::chunk_generator::ChunkGenerator>();
|
||||
let chunk_pos = self.terrain().pos_key(pos.0.map(|e| e as i32));
|
||||
(-(view_distance as i32)..view_distance as i32 + 1)
|
||||
.flat_map(|x| {
|
||||
(-(view_distance as i32)..view_distance as i32 + 1).map(move |y| Vec2::new(x, y))
|
||||
})
|
||||
.map(|offset| offset + chunk_pos)
|
||||
// Filter chunks outside the view distance
|
||||
// Note: calculation from client chunk request filtering
|
||||
.filter(|chunk_key| {
|
||||
pos.0.xy().map(|e| e as f64).distance(
|
||||
chunk_key.map(|e| e as f64 + 0.5) * TerrainChunkSize::RECT_SIZE.map(|e| e as f64),
|
||||
) < (view_distance as f64 - 1.0 + 2.5 * 2.0_f64.sqrt())
|
||||
* TerrainChunkSize::RECT_SIZE.x as f64
|
||||
})
|
||||
.for_each(|chunk_key| {
|
||||
chunk_generator.generate_chunk(None, chunk_key, runtime, Arc::clone(world), index.clone());
|
||||
});
|
||||
}
|
||||
|
||||
self.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(Presence::new(view_distance, PresenceKind::Spectator))
|
||||
}
|
||||
|
||||
fn initialize_character_data(&mut self, entity: EcsEntity, character_id: CharacterId) {
|
||||
let spawn_point = self.ecs().read_resource::<SpawnPoint>().0;
|
||||
|
||||
|
@ -23,6 +23,7 @@ use common::{
|
||||
util::Dir,
|
||||
vol::ReadVol,
|
||||
};
|
||||
use common_base::prof_span;
|
||||
use common_ecs::{Job, Origin, ParMode, Phase, System};
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::iter::ParallelIterator;
|
||||
@ -141,8 +142,13 @@ impl<'a> System<'a> for Sys {
|
||||
.map(|ms| *ms == MountState::Unmounted)
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.for_each(
|
||||
|(
|
||||
.for_each_init(
|
||||
|| {
|
||||
prof_span!(guard, "agent rayon job");
|
||||
guard
|
||||
},
|
||||
|_guard,
|
||||
(
|
||||
entity,
|
||||
(energy, health),
|
||||
pos,
|
||||
|
@ -43,10 +43,10 @@ pub fn init(settings: &Settings) -> Vec<impl Drop> {
|
||||
env.add_directive("dot_vox::parser=warn".parse().unwrap())
|
||||
.add_directive("gfx_device_gl=warn".parse().unwrap())
|
||||
.add_directive("prometheus_hyper=warn".parse().unwrap())
|
||||
.add_directive("mio::sys::windows=debug".parse().unwrap())
|
||||
.add_directive("mio::sys::windows=info".parse().unwrap())
|
||||
.add_directive("h2=info".parse().unwrap())
|
||||
.add_directive("tokio_util=info".parse().unwrap())
|
||||
.add_directive("rustls=debug".parse().unwrap())
|
||||
.add_directive("rustls=info".parse().unwrap())
|
||||
.add_directive("veloren_network_protocol=info".parse().unwrap())
|
||||
.add_directive(
|
||||
"veloren_server::persistence::character=info"
|
||||
|
Loading…
Reference in New Issue
Block a user