mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'xMAC94x/advanced_systems' into 'master'
Implement a VSystem trait that can be implemented by Systems. See merge request veloren/veloren!1858
This commit is contained in:
commit
8c1ac78ce3
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -1643,6 +1643,15 @@ dependencies = [
|
||||
"miniz_oxide 0.4.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float-cmp"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -5598,6 +5607,7 @@ dependencies = [
|
||||
"directories-next",
|
||||
"dot_vox",
|
||||
"enum-iterator",
|
||||
"float-cmp",
|
||||
"hashbrown 0.9.1",
|
||||
"image",
|
||||
"indexmap",
|
||||
@ -6681,4 +6691,4 @@ dependencies = [
|
||||
name = "xml-rs"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
|
||||
checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a"
|
@ -68,6 +68,7 @@ specs-idvs = { git = "https://gitlab.com/veloren/specs-idvs.git", rev = "9fab7b3
|
||||
[dev-dependencies]
|
||||
#bench
|
||||
criterion = "0.3"
|
||||
float-cmp = "0.8.0"
|
||||
|
||||
[[bench]]
|
||||
name = "chonk_benchmark"
|
||||
|
@ -61,6 +61,7 @@ pub mod spiral;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod states;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod store;
|
||||
pub mod system;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod terrain;
|
||||
#[cfg(not(target_arch = "wasm32"))] pub mod time;
|
||||
|
@ -1,15 +1,9 @@
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use crate::system::CpuTimeline;
|
||||
use std::{collections::HashMap, sync::Mutex};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SysMetrics {
|
||||
pub agent_ns: AtomicU64,
|
||||
pub mount_ns: AtomicU64,
|
||||
pub controller_ns: AtomicU64,
|
||||
pub character_behavior_ns: AtomicU64,
|
||||
pub stats_ns: AtomicU64,
|
||||
pub phys_ns: AtomicU64,
|
||||
pub projectile_ns: AtomicU64,
|
||||
pub melee_ns: AtomicU64,
|
||||
pub stats: Mutex<HashMap<String, CpuTimeline>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
458
common/src/system.rs
Normal file
458
common/src/system.rs
Normal file
@ -0,0 +1,458 @@
|
||||
use crate::metrics::SysMetrics;
|
||||
use specs::{ReadExpect, RunNow};
|
||||
use std::{collections::HashMap, time::Instant};
|
||||
|
||||
/// measuring the level of threads a unit of code ran on. Use Rayon when it ran
|
||||
/// on their threadpool. Use Exact when you know on how many threads your code
|
||||
/// ran on exactly.
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum ParMode {
|
||||
None, /* Job is not running at all */
|
||||
Single,
|
||||
Rayon,
|
||||
Exact(u16),
|
||||
}
|
||||
|
||||
//TODO: make use of the phase of a system for advanced scheduling and logging
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum Phase {
|
||||
Create,
|
||||
Review,
|
||||
Apply,
|
||||
}
|
||||
|
||||
//TODO: make use of the origin of the system for better logging
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub enum Origin {
|
||||
Common,
|
||||
Client,
|
||||
Server,
|
||||
Frontend(&'static str),
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct CpuTimeline {
|
||||
/// measurements for a System
|
||||
/// - The first entry will always be ParMode::Single, as when the
|
||||
/// System::run is executed, we run
|
||||
/// single threaded until we start a Rayon::ParIter or similar
|
||||
/// - The last entry will contain the end time of the System. To mark the
|
||||
/// End it will always contain
|
||||
/// ParMode::None, which means from that point on 0 CPU threads work in this
|
||||
/// system
|
||||
measures: Vec<(Instant, ParMode)>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CpuTimeStats {
|
||||
/// the first entry will always be 0, the last entry will always be `dt`
|
||||
/// `usage` starting from `ns`
|
||||
measures: Vec<(/* ns */ u64, /* usage */ f32)>,
|
||||
}
|
||||
|
||||
/// Parallel Mode tells us how much you are scaling. `None` means your code
|
||||
/// isn't running. `Single` means you are running single threaded.
|
||||
/// `Rayon` means you are running on the rayon threadpool.
|
||||
impl ParMode {
|
||||
fn threads(&self, rayon_threads: u16) -> u16 {
|
||||
match self {
|
||||
ParMode::None => 0,
|
||||
ParMode::Single => 1,
|
||||
ParMode::Rayon => rayon_threads,
|
||||
ParMode::Exact(u) => *u,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CpuTimeline {
|
||||
fn reset(&mut self) {
|
||||
self.measures.clear();
|
||||
self.measures.push((Instant::now(), ParMode::Single));
|
||||
}
|
||||
|
||||
/// Start a new measurement. par will be covering the parallelisation AFTER
|
||||
/// this statement, till the next / end of the System.
|
||||
pub fn measure(&mut self, par: ParMode) { self.measures.push((Instant::now(), par)); }
|
||||
|
||||
fn end(&mut self) { self.measures.push((Instant::now(), ParMode::None)); }
|
||||
|
||||
fn get(&self, time: Instant) -> ParMode {
|
||||
match self.measures.binary_search_by_key(&time, |&(a, _)| a) {
|
||||
Ok(id) => self.measures[id].1,
|
||||
Err(0) => ParMode::None, /* not yet started */
|
||||
Err(id) => self.measures[id - 1].1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CpuTimeStats {
|
||||
pub fn length_ns(&self) -> u64 { self.end_ns() - self.start_ns() }
|
||||
|
||||
pub fn start_ns(&self) -> u64 {
|
||||
self.measures
|
||||
.iter()
|
||||
.find(|e| e.1 > 0.001)
|
||||
.unwrap_or(&(0, 0.0))
|
||||
.0
|
||||
}
|
||||
|
||||
pub fn end_ns(&self) -> u64 { self.measures.last().unwrap_or(&(0, 0.0)).0 }
|
||||
|
||||
pub fn avg_threads(&self) -> f32 {
|
||||
let mut sum = 0.0;
|
||||
for w in self.measures.windows(2) {
|
||||
let len = w[1].0 - w[0].0;
|
||||
let h = w[0].1;
|
||||
sum += len as f32 * h;
|
||||
}
|
||||
sum / (self.length_ns() as f32)
|
||||
}
|
||||
}
|
||||
|
||||
/// The Idea is to transform individual timelines per system to a map of all
|
||||
/// cores and what they (prob) are working on.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// - Input: 3 services, 0 and 1 are 100% parallel and 2 is single threaded. `-`
|
||||
/// means no work for *0.5s*. `#` means full work for *0.5s*. We see the first
|
||||
/// service starts after 1s and runs for 3s The second one starts a sec later
|
||||
/// and runs for 4s. The last service runs 2.5s after the tick start and runs
|
||||
/// for 1s. Read left to right.
|
||||
/// ```ignore
|
||||
/// [--######------]
|
||||
/// [----########--]
|
||||
/// [-----##-------]
|
||||
/// ```
|
||||
///
|
||||
/// - Output: a Map that calculates where our 6 cores are spending their time.
|
||||
/// Here each number means 50% of a core is working on it. A '-' represents an
|
||||
/// idling core. We start with all 6 cores idling. Then all cores start to
|
||||
/// work on task 0. 2s in, task1 starts and we have to split cores. 2.5s in
|
||||
/// task2 starts. We have 6 physical threads but work to fill 13. Later task 2
|
||||
/// and task 0 will finish their work and give more threads for task 1 to work
|
||||
/// on. Read top to bottom
|
||||
/// ```ignore
|
||||
/// 0-1s [------------]
|
||||
/// 1-2s [000000000000]
|
||||
/// 2-2.5s [000000111111]
|
||||
/// 2.5-3.5s [000001111122]
|
||||
/// 3.5-4s [000000111111]
|
||||
/// 4-6s [111111111111]
|
||||
/// 6s.. [------------]
|
||||
/// ```
|
||||
pub fn gen_stats(
|
||||
timelines: &HashMap<String, CpuTimeline>,
|
||||
tick_work_start: Instant,
|
||||
rayon_threads: u16,
|
||||
physical_threads: u16,
|
||||
) -> HashMap<String, CpuTimeStats> {
|
||||
let mut result = HashMap::new();
|
||||
let mut all = timelines
|
||||
.iter()
|
||||
.map(|(s, t)| {
|
||||
let mut stat = CpuTimeStats::default();
|
||||
stat.measures.push((0, 0.0));
|
||||
result.insert(s.clone(), stat);
|
||||
t.measures.iter().map(|e| &e.0)
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
all.sort();
|
||||
all.dedup();
|
||||
for time in all {
|
||||
let relative_time = time.duration_since(tick_work_start).as_nanos() as u64;
|
||||
// get all parallelisation at this particular time
|
||||
let individual_cores_wanted = timelines
|
||||
.iter()
|
||||
.map(|(k, t)| (k, t.get(*time).threads(rayon_threads)))
|
||||
.collect::<Vec<_>>();
|
||||
let total = individual_cores_wanted
|
||||
.iter()
|
||||
.map(|(_, a)| a)
|
||||
.sum::<u16>()
|
||||
.max(1) as f32;
|
||||
let total_or_max = total.max(physical_threads as f32);
|
||||
// update ALL states
|
||||
for individual in individual_cores_wanted.iter() {
|
||||
let actual = (individual.1 as f32 / total_or_max) * physical_threads as f32;
|
||||
let p = result.get_mut(individual.0).unwrap();
|
||||
if (p.measures.last().unwrap().1 - actual).abs() > 0.0001 {
|
||||
p.measures.push((relative_time, actual));
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// This trait wraps around specs::System and does additional veloren tasks like
|
||||
/// metrics collection
|
||||
///
|
||||
/// ```
|
||||
/// use specs::Read;
|
||||
/// pub use veloren_common::system::{Job, Origin, ParMode, Phase, System};
|
||||
/// # use std::time::Duration;
|
||||
/// pub struct Sys;
|
||||
/// impl<'a> System<'a> for Sys {
|
||||
/// type SystemData = (Read<'a, ()>, Read<'a, ()>);
|
||||
///
|
||||
/// const NAME: &'static str = "example";
|
||||
/// const ORIGIN: Origin = Origin::Frontend("voxygen");
|
||||
/// const PHASE: Phase = Phase::Create;
|
||||
///
|
||||
/// fn run(job: &mut Job<Self>, (_read, _read2): Self::SystemData) {
|
||||
/// std::thread::sleep(Duration::from_millis(100));
|
||||
/// job.cpu_stats.measure(ParMode::Rayon);
|
||||
/// std::thread::sleep(Duration::from_millis(500));
|
||||
/// job.cpu_stats.measure(ParMode::Single);
|
||||
/// std::thread::sleep(Duration::from_millis(40));
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait System<'a> {
|
||||
const NAME: &'static str;
|
||||
const PHASE: Phase;
|
||||
const ORIGIN: Origin;
|
||||
|
||||
type SystemData: specs::SystemData<'a>;
|
||||
fn run(job: &mut Job<Self>, data: Self::SystemData);
|
||||
fn sys_name() -> String { format!("{}_sys", Self::NAME) }
|
||||
}
|
||||
|
||||
pub fn dispatch<'a, 'b, T>(builder: &mut specs::DispatcherBuilder<'a, 'b>, dep: &[&str])
|
||||
where
|
||||
T: for<'c> System<'c> + Send + 'a + Default,
|
||||
{
|
||||
builder.add(Job::<T>::default(), &T::sys_name(), dep);
|
||||
}
|
||||
|
||||
pub fn run_now<'a, 'b, T>(world: &'a specs::World)
|
||||
where
|
||||
T: for<'c> System<'c> + Send + 'a + Default,
|
||||
{
|
||||
Job::<T>::default().run_now(world);
|
||||
}
|
||||
|
||||
/// This Struct will wrap the System in order to avoid the can only impl trait
|
||||
/// for local defined structs error It also contains the cpu measurements
|
||||
pub struct Job<T>
|
||||
where
|
||||
T: ?Sized,
|
||||
{
|
||||
pub own: Box<T>,
|
||||
pub cpu_stats: CpuTimeline,
|
||||
}
|
||||
|
||||
impl<'a, T> specs::System<'a> for Job<T>
|
||||
where
|
||||
T: System<'a>,
|
||||
{
|
||||
type SystemData = (T::SystemData, ReadExpect<'a, SysMetrics>);
|
||||
|
||||
fn run(&mut self, data: Self::SystemData) {
|
||||
crate::span!(_guard, "run", &format!("{}::Sys::run", T::NAME));
|
||||
self.cpu_stats.reset();
|
||||
T::run(self, data.0);
|
||||
self.cpu_stats.end();
|
||||
data.1
|
||||
.stats
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(T::NAME.to_string(), self.cpu_stats.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Default for Job<T>
|
||||
where
|
||||
T: System<'a> + Default,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
own: Box::new(T::default()),
|
||||
cpu_stats: CpuTimeline::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use float_cmp::approx_eq;
|
||||
use std::time::Duration;
|
||||
|
||||
fn mock_timelines(
|
||||
tick_start: Instant,
|
||||
durations: Vec<(u64, u64, ParMode)>,
|
||||
) -> HashMap<String, CpuTimeline> {
|
||||
let job = durations
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, (s, e, p))| {
|
||||
(
|
||||
i,
|
||||
tick_start + Duration::from_millis(*s),
|
||||
tick_start + Duration::from_millis(*e),
|
||||
*p,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
job.iter()
|
||||
.map(|(i, f, s, p)| {
|
||||
(i.to_string(), CpuTimeline {
|
||||
measures: vec![(*f, *p), (*s, ParMode::None)],
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single() {
|
||||
const RAYON_THREADS: u16 = 4;
|
||||
const PHYSICAL_THREADS: u16 = RAYON_THREADS;
|
||||
let tick_start = Instant::now();
|
||||
let job_d = vec![(500, 1500, ParMode::Rayon)];
|
||||
let timelines = mock_timelines(tick_start, job_d);
|
||||
|
||||
let stats = gen_stats(&timelines, tick_start, RAYON_THREADS, PHYSICAL_THREADS);
|
||||
|
||||
const THREADS: f32 = PHYSICAL_THREADS as f32;
|
||||
|
||||
let s = &stats["0"];
|
||||
let measures = &s.measures;
|
||||
assert_eq!(measures.len(), 3);
|
||||
assert_eq!(measures[0].0, 0);
|
||||
assert!(approx_eq!(f32, measures[0].1, 0.0));
|
||||
assert_eq!(measures[1].0, 500000000);
|
||||
assert!(approx_eq!(f32, measures[1].1, THREADS));
|
||||
assert_eq!(measures[2].0, 1500000000);
|
||||
assert!(approx_eq!(f32, measures[2].1, 0.0));
|
||||
assert_eq!(s.start_ns(), 500000000);
|
||||
assert_eq!(s.end_ns(), 1500000000);
|
||||
assert_eq!(s.length_ns(), 1000000000);
|
||||
assert!(approx_eq!(f32, s.avg_threads(), THREADS));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_jobs() {
|
||||
const RAYON_THREADS: u16 = 8;
|
||||
const PHYSICAL_THREADS: u16 = RAYON_THREADS;
|
||||
let tick_start = Instant::now();
|
||||
let job_d = vec![(2000, 3000, ParMode::Single), (5000, 6500, ParMode::Single)];
|
||||
let timelines = mock_timelines(tick_start, job_d);
|
||||
|
||||
let stats = gen_stats(&timelines, tick_start, RAYON_THREADS, PHYSICAL_THREADS);
|
||||
|
||||
let s = &stats["0"];
|
||||
let measures = &s.measures;
|
||||
assert_eq!(measures.len(), 3);
|
||||
assert_eq!(measures[0].0, 0);
|
||||
assert!(approx_eq!(f32, measures[0].1, 0.0));
|
||||
assert_eq!(measures[1].0, 2000000000);
|
||||
assert!(approx_eq!(f32, measures[1].1, 1.0));
|
||||
assert_eq!(measures[2].0, 3000000000);
|
||||
assert!(approx_eq!(f32, measures[2].1, 0.0));
|
||||
assert_eq!(s.start_ns(), 2000000000);
|
||||
assert_eq!(s.end_ns(), 3000000000);
|
||||
assert_eq!(s.length_ns(), 1000000000);
|
||||
assert!(approx_eq!(f32, s.avg_threads(), 1.0));
|
||||
|
||||
let s = &stats["1"];
|
||||
let measures = &s.measures;
|
||||
assert_eq!(measures.len(), 3);
|
||||
assert_eq!(measures[0].0, 0);
|
||||
assert!(approx_eq!(f32, measures[0].1, 0.0));
|
||||
assert_eq!(measures[1].0, 5000000000);
|
||||
assert!(approx_eq!(f32, measures[1].1, 1.0));
|
||||
assert_eq!(measures[2].0, 6500000000);
|
||||
assert!(approx_eq!(f32, measures[2].1, 0.0));
|
||||
assert_eq!(s.start_ns(), 5000000000);
|
||||
assert_eq!(s.end_ns(), 6500000000);
|
||||
assert_eq!(s.length_ns(), 1500000000);
|
||||
assert!(approx_eq!(f32, s.avg_threads(), 1.0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generate_stats() {
|
||||
const RAYON_THREADS: u16 = 6;
|
||||
const PHYSICAL_THREADS: u16 = RAYON_THREADS;
|
||||
let tick_start = Instant::now();
|
||||
let job_d = vec![
|
||||
(2000, 5000, ParMode::Rayon),
|
||||
(3000, 7000, ParMode::Rayon),
|
||||
(3500, 4500, ParMode::Single),
|
||||
];
|
||||
let timelines = mock_timelines(tick_start, job_d);
|
||||
|
||||
let stats = gen_stats(&timelines, tick_start, RAYON_THREADS, PHYSICAL_THREADS);
|
||||
|
||||
const THREADS: f32 = PHYSICAL_THREADS as f32;
|
||||
|
||||
let s = &stats["0"];
|
||||
let measures = &s.measures;
|
||||
assert_eq!(measures.len(), 6);
|
||||
assert_eq!(measures[0].0, 0);
|
||||
assert!(approx_eq!(f32, measures[0].1, 0.0));
|
||||
assert_eq!(measures[1].0, 2000000000);
|
||||
assert!(approx_eq!(f32, measures[1].1, THREADS));
|
||||
assert_eq!(measures[2].0, 3000000000);
|
||||
assert!(approx_eq!(f32, measures[2].1, THREADS / 2.0));
|
||||
assert_eq!(measures[3].0, 3500000000);
|
||||
assert!(approx_eq!(
|
||||
f32,
|
||||
measures[3].1,
|
||||
THREADS * THREADS / (THREADS * 2.0 + 1.0)
|
||||
));
|
||||
assert_eq!(measures[4].0, 4500000000);
|
||||
assert!(approx_eq!(f32, measures[4].1, THREADS / 2.0));
|
||||
assert_eq!(measures[5].0, 5000000000);
|
||||
assert!(approx_eq!(f32, measures[5].1, 0.0));
|
||||
assert_eq!(s.start_ns(), 2000000000);
|
||||
assert_eq!(s.end_ns(), 5000000000);
|
||||
assert_eq!(s.length_ns(), 3000000000);
|
||||
assert!(approx_eq!(f32, s.avg_threads(), 3.923077));
|
||||
|
||||
let s = &stats["1"];
|
||||
let measures = &s.measures;
|
||||
assert_eq!(measures.len(), 6);
|
||||
assert_eq!(measures[0].0, 0);
|
||||
assert!(approx_eq!(f32, measures[0].1, 0.0));
|
||||
assert_eq!(measures[1].0, 3000000000);
|
||||
assert!(approx_eq!(f32, measures[1].1, THREADS / 2.0));
|
||||
assert_eq!(measures[2].0, 3500000000);
|
||||
assert!(approx_eq!(
|
||||
f32,
|
||||
measures[2].1,
|
||||
THREADS * THREADS / (THREADS * 2.0 + 1.0)
|
||||
));
|
||||
assert_eq!(measures[3].0, 4500000000);
|
||||
assert!(approx_eq!(f32, measures[3].1, THREADS / 2.0));
|
||||
assert_eq!(measures[4].0, 5000000000);
|
||||
assert!(approx_eq!(f32, measures[4].1, THREADS));
|
||||
assert_eq!(measures[5].0, 7000000000);
|
||||
assert!(approx_eq!(f32, measures[5].1, 0.0));
|
||||
assert_eq!(s.start_ns(), 3000000000);
|
||||
assert_eq!(s.end_ns(), 7000000000);
|
||||
assert_eq!(s.length_ns(), 4000000000);
|
||||
assert!(approx_eq!(f32, s.avg_threads(), 4.4423075));
|
||||
|
||||
let s = &stats["2"];
|
||||
let measures = &s.measures;
|
||||
assert_eq!(measures.len(), 3);
|
||||
assert_eq!(measures[0].0, 0);
|
||||
assert!(approx_eq!(f32, measures[0].1, 0.0));
|
||||
assert_eq!(measures[1].0, 3500000000);
|
||||
assert!(approx_eq!(
|
||||
f32,
|
||||
measures[1].1,
|
||||
THREADS / (THREADS * 2.0 + 1.0)
|
||||
));
|
||||
assert_eq!(measures[2].0, 4500000000);
|
||||
assert!(approx_eq!(f32, measures[2].1, 0.0));
|
||||
assert_eq!(s.start_ns(), 3500000000);
|
||||
assert_eq!(s.end_ns(), 4500000000);
|
||||
assert_eq!(s.length_ns(), 1000000000);
|
||||
assert!(approx_eq!(f32, s.avg_threads(), 0.4615385));
|
||||
}
|
||||
}
|
@ -7,11 +7,12 @@ use common::{
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::DeltaTime,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::UidAllocator,
|
||||
};
|
||||
use specs::{
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, System,
|
||||
SystemData, World, WriteStorage,
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData,
|
||||
World, WriteStorage,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
@ -27,6 +28,7 @@ pub struct ReadData<'a> {
|
||||
groups: ReadStorage<'a, Group>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
@ -35,7 +37,11 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Buffs>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (read_data, mut auras, mut buffs): Self::SystemData) {
|
||||
const NAME: &'static str = "aura";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(_job: &mut Job<Self>, (read_data, mut auras, mut buffs): Self::SystemData) {
|
||||
let mut server_emitter = read_data.server_bus.emitter();
|
||||
let dt = read_data.dt.0;
|
||||
|
||||
|
@ -6,12 +6,13 @@ use common::{
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::{DeltaTime, Time},
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::{Uid, UidAllocator},
|
||||
GroupTarget,
|
||||
};
|
||||
use specs::{
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, System,
|
||||
SystemData, World, WriteStorage,
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData,
|
||||
World, WriteStorage,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
@ -37,6 +38,7 @@ pub struct ReadData<'a> {
|
||||
}
|
||||
|
||||
/// This system is responsible for handling beams that heal or do damage
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
@ -45,7 +47,11 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Beam>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (read_data, mut beam_segments, mut beams): Self::SystemData) {
|
||||
const NAME: &'static str = "beam";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(_job: &mut Job<Self>, (read_data, mut beam_segments, mut beams): Self::SystemData) {
|
||||
let mut server_emitter = read_data.server_bus.emitter();
|
||||
|
||||
let time = read_data.time.0;
|
||||
|
@ -5,10 +5,11 @@ use common::{
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::DeltaTime,
|
||||
system::{Job, Origin, Phase, System},
|
||||
Damage, DamageSource,
|
||||
};
|
||||
use specs::{
|
||||
shred::ResourceId, Entities, Join, Read, ReadStorage, System, SystemData, World, WriteStorage,
|
||||
shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData, World, WriteStorage,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
@ -20,6 +21,7 @@ pub struct ReadData<'a> {
|
||||
inventories: ReadStorage<'a, Inventory>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
@ -30,8 +32,12 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Stats>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "buff";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(read_data, mut healths, mut energies, mut buffs, mut stats): Self::SystemData,
|
||||
) {
|
||||
let mut server_emitter = read_data.server_bus.emitter();
|
||||
|
@ -1,6 +1,6 @@
|
||||
use specs::{
|
||||
shred::ResourceId, Entities, Join, LazyUpdate, Read, ReadExpect, ReadStorage, System,
|
||||
SystemData, World, WriteStorage,
|
||||
shred::ResourceId, Entities, Join, LazyUpdate, Read, ReadStorage, SystemData, World,
|
||||
WriteStorage,
|
||||
};
|
||||
|
||||
use common::{
|
||||
@ -13,13 +13,12 @@ use common::{
|
||||
Ori, PhysicsState, Poise, PoiseState, Pos, StateUpdate, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
resources::DeltaTime,
|
||||
span,
|
||||
states::{
|
||||
self,
|
||||
behavior::{CharacterBehavior, JoinData, JoinStruct},
|
||||
},
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::Uid,
|
||||
};
|
||||
use std::time::Duration;
|
||||
@ -56,7 +55,6 @@ pub struct ReadData<'a> {
|
||||
local_bus: Read<'a, EventBus<LocalEvent>>,
|
||||
dt: Read<'a, DeltaTime>,
|
||||
lazy_update: Read<'a, LazyUpdate>,
|
||||
metrics: ReadExpect<'a, SysMetrics>,
|
||||
healths: ReadStorage<'a, Health>,
|
||||
bodies: ReadStorage<'a, Body>,
|
||||
physics_states: ReadStorage<'a, PhysicsState>,
|
||||
@ -72,6 +70,7 @@ pub struct ReadData<'a> {
|
||||
/// ## Character Behavior System
|
||||
/// Passes `JoinData` to `CharacterState`'s `behavior` handler fn's. Receives a
|
||||
/// `StateUpdate` in return and performs updates to ECS Components from that.
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
@ -88,9 +87,13 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Poise>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "character_behavior";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
#[allow(clippy::while_let_on_iterator)] // TODO: Pending review in #587
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
read_data,
|
||||
mut character_states,
|
||||
@ -103,8 +106,6 @@ impl<'a> System<'a> for Sys {
|
||||
mut poises,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let start_time = std::time::Instant::now();
|
||||
span!(_guard, "run", "character_behavior::Sys::run");
|
||||
let mut server_emitter = read_data.server_bus.emitter();
|
||||
let mut local_emitter = read_data.local_bus.emitter();
|
||||
|
||||
@ -347,9 +348,5 @@ impl<'a> System<'a> for Sys {
|
||||
server_emitter.append(&mut state_update.server_events);
|
||||
incorporate_update(&mut join_struct, state_update);
|
||||
}
|
||||
read_data.metrics.character_behavior_ns.store(
|
||||
start_time.elapsed().as_nanos() as u64,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
use common::{
|
||||
comp::{BuffChange, ControlEvent, Controller},
|
||||
event::{EventBus, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::UidAllocator,
|
||||
};
|
||||
use specs::{
|
||||
saveload::{Marker, MarkerAllocator},
|
||||
shred::ResourceId,
|
||||
Entities, Join, Read, ReadExpect, System, SystemData, World, WriteStorage,
|
||||
Entities, Join, Read, SystemData, World, WriteStorage,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
@ -17,17 +16,19 @@ pub struct ReadData<'a> {
|
||||
entities: Entities<'a>,
|
||||
uid_allocator: Read<'a, UidAllocator>,
|
||||
server_bus: Read<'a, EventBus<ServerEvent>>,
|
||||
metrics: ReadExpect<'a, SysMetrics>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (ReadData<'a>, WriteStorage<'a, Controller>);
|
||||
|
||||
fn run(&mut self, (read_data, mut controllers): Self::SystemData) {
|
||||
let start_time = std::time::Instant::now();
|
||||
span!(_guard, "run", "controller::Sys::run");
|
||||
const NAME: &'static str = "controller";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(_job: &mut Job<Self>, (read_data, mut controllers): Self::SystemData) {
|
||||
let mut server_emitter = read_data.server_bus.emitter();
|
||||
|
||||
for (entity, controller) in (&read_data.entities, &mut controllers).join() {
|
||||
@ -103,9 +104,5 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
}
|
||||
read_data.metrics.controller_ns.store(
|
||||
start_time.elapsed().as_nanos() as u64,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -15,33 +15,23 @@ pub mod state;
|
||||
mod stats;
|
||||
|
||||
// External
|
||||
use common::system::{dispatch, System};
|
||||
use specs::DispatcherBuilder;
|
||||
|
||||
// System names
|
||||
pub const CHARACTER_BEHAVIOR_SYS: &str = "character_behavior_sys";
|
||||
pub const MELEE_SYS: &str = "melee_sys";
|
||||
pub const BEAM_SYS: &str = "beam_sys";
|
||||
pub const CONTROLLER_SYS: &str = "controller_sys";
|
||||
pub const MOUNT_SYS: &str = "mount_sys";
|
||||
pub const PHYS_SYS: &str = "phys_sys";
|
||||
pub const PROJECTILE_SYS: &str = "projectile_sys";
|
||||
pub const SHOCKWAVE_SYS: &str = "shockwave_sys";
|
||||
pub const STATS_SYS: &str = "stats_sys";
|
||||
pub const BUFFS_SYS: &str = "buffs_sys";
|
||||
pub const AURAS_SYS: &str = "auras_sys";
|
||||
|
||||
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch_builder.add(mount::Sys, MOUNT_SYS, &[]);
|
||||
dispatch_builder.add(controller::Sys, CONTROLLER_SYS, &[MOUNT_SYS]);
|
||||
dispatch_builder.add(character_behavior::Sys, CHARACTER_BEHAVIOR_SYS, &[
|
||||
CONTROLLER_SYS,
|
||||
dispatch::<mount::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<controller::Sys>(dispatch_builder, &[&mount::Sys::sys_name()]);
|
||||
dispatch::<character_behavior::Sys>(dispatch_builder, &[&controller::Sys::sys_name()]);
|
||||
dispatch::<stats::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<buff::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<phys::Sys>(dispatch_builder, &[
|
||||
&controller::Sys::sys_name(),
|
||||
&mount::Sys::sys_name(),
|
||||
&stats::Sys::sys_name(),
|
||||
]);
|
||||
dispatch_builder.add(stats::Sys, STATS_SYS, &[]);
|
||||
dispatch_builder.add(buff::Sys, BUFFS_SYS, &[]);
|
||||
dispatch_builder.add(phys::Sys, PHYS_SYS, &[CONTROLLER_SYS, MOUNT_SYS, STATS_SYS]);
|
||||
dispatch_builder.add(projectile::Sys, PROJECTILE_SYS, &[PHYS_SYS]);
|
||||
dispatch_builder.add(shockwave::Sys, SHOCKWAVE_SYS, &[PHYS_SYS]);
|
||||
dispatch_builder.add(beam::Sys, BEAM_SYS, &[PHYS_SYS]);
|
||||
dispatch_builder.add(melee::Sys, MELEE_SYS, &[PROJECTILE_SYS]);
|
||||
dispatch_builder.add(aura::Sys, AURAS_SYS, &[]);
|
||||
dispatch::<projectile::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
|
||||
dispatch::<shockwave::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
|
||||
dispatch::<beam::Sys>(dispatch_builder, &[&phys::Sys::sys_name()]);
|
||||
dispatch::<melee::Sys>(dispatch_builder, &[&projectile::Sys::sys_name()]);
|
||||
dispatch::<aura::Sys>(dispatch_builder, &[]);
|
||||
}
|
||||
|
@ -2,15 +2,13 @@ use common::{
|
||||
combat::{AttackerInfo, TargetInfo},
|
||||
comp::{Body, CharacterState, Energy, Group, Health, Inventory, Melee, Ori, Pos, Scale, Stats},
|
||||
event::{EventBus, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::Uid,
|
||||
util::Dir,
|
||||
GroupTarget,
|
||||
};
|
||||
use specs::{
|
||||
shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage, System, SystemData, World,
|
||||
WriteStorage,
|
||||
shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData, World, WriteStorage,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
@ -28,20 +26,22 @@ pub struct ReadData<'a> {
|
||||
groups: ReadStorage<'a, Group>,
|
||||
char_states: ReadStorage<'a, CharacterState>,
|
||||
server_bus: Read<'a, EventBus<ServerEvent>>,
|
||||
metrics: ReadExpect<'a, SysMetrics>,
|
||||
stats: ReadStorage<'a, Stats>,
|
||||
}
|
||||
|
||||
/// This system is responsible for handling accepted inputs like moving or
|
||||
/// attacking
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (ReadData<'a>, WriteStorage<'a, Melee>);
|
||||
|
||||
fn run(&mut self, (read_data, mut melee_attacks): Self::SystemData) {
|
||||
let start_time = std::time::Instant::now();
|
||||
span!(_guard, "run", "melee::Sys::run");
|
||||
const NAME: &'static str = "melee";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(_job: &mut Job<Self>, (read_data, mut melee_attacks): Self::SystemData) {
|
||||
let mut server_emitter = read_data.server_bus.emitter();
|
||||
// Attacks
|
||||
for (attacker, uid, pos, ori, melee_attack, body) in (
|
||||
@ -135,9 +135,5 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
}
|
||||
read_data.metrics.melee_ns.store(
|
||||
start_time.elapsed().as_nanos() as u64,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,21 @@
|
||||
use common::{
|
||||
comp::{Controller, MountState, Mounting, Ori, Pos, Vel},
|
||||
metrics::SysMetrics,
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::UidAllocator,
|
||||
};
|
||||
use specs::{
|
||||
saveload::{Marker, MarkerAllocator},
|
||||
Entities, Join, Read, ReadExpect, System, WriteStorage,
|
||||
Entities, Join, Read, WriteStorage,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
/// This system is responsible for controlling mounts
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Read<'a, UidAllocator>,
|
||||
ReadExpect<'a, SysMetrics>,
|
||||
Entities<'a>,
|
||||
WriteStorage<'a, Controller>,
|
||||
WriteStorage<'a, MountState>,
|
||||
@ -26,11 +25,14 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Ori>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "mount";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
uid_allocator,
|
||||
sys_metrics,
|
||||
entities,
|
||||
mut controllers,
|
||||
mut mount_state,
|
||||
@ -40,8 +42,6 @@ impl<'a> System<'a> for Sys {
|
||||
mut orientations,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let start_time = std::time::Instant::now();
|
||||
span!(_guard, "run", "mount::Sys::run");
|
||||
// Mounted entities.
|
||||
for (entity, mut mount_states) in (&entities, &mut mount_state.restrict_mut()).join() {
|
||||
match mount_states.get_unchecked() {
|
||||
@ -92,9 +92,5 @@ impl<'a> System<'a> for Sys {
|
||||
for entity in to_unmount {
|
||||
mountings.remove(entity);
|
||||
}
|
||||
sys_metrics.mount_ns.store(
|
||||
start_time.elapsed().as_nanos() as u64,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,17 +5,16 @@ use common::{
|
||||
},
|
||||
consts::{FRIC_GROUND, GRAVITY},
|
||||
event::{EventBus, ServerEvent},
|
||||
metrics::{PhysicsMetrics, SysMetrics},
|
||||
metrics::PhysicsMetrics,
|
||||
resources::DeltaTime,
|
||||
span,
|
||||
system::{Job, Origin, ParMode, Phase, System},
|
||||
terrain::{Block, TerrainGrid},
|
||||
uid::Uid,
|
||||
vol::ReadVol,
|
||||
};
|
||||
use rayon::iter::ParallelIterator;
|
||||
use specs::{
|
||||
Entities, Join, ParJoin, Read, ReadExpect, ReadStorage, System, WriteExpect, WriteStorage,
|
||||
};
|
||||
use specs::{Entities, Join, ParJoin, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
|
||||
use std::ops::Range;
|
||||
use vek::*;
|
||||
|
||||
@ -61,6 +60,7 @@ fn calc_z_limit(
|
||||
}
|
||||
|
||||
/// This system applies forces and calculates new positions and velocities.
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
@ -70,7 +70,6 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadExpect<'a, SysMetrics>,
|
||||
WriteExpect<'a, PhysicsMetrics>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
ReadStorage<'a, Scale>,
|
||||
@ -90,16 +89,19 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, CharacterState>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "phys";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
||||
#[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587
|
||||
fn run(
|
||||
&mut self,
|
||||
job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
uids,
|
||||
terrain,
|
||||
dt,
|
||||
sys_metrics,
|
||||
mut physics_metrics,
|
||||
event_bus,
|
||||
scales,
|
||||
@ -119,8 +121,6 @@ impl<'a> System<'a> for Sys {
|
||||
char_states,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let start_time = std::time::Instant::now();
|
||||
span!(_guard, "run", "phys::Sys::run");
|
||||
let mut event_emitter = event_bus.emitter();
|
||||
|
||||
// Add/reset physics state components
|
||||
@ -212,6 +212,7 @@ impl<'a> System<'a> for Sys {
|
||||
drop(guard);
|
||||
|
||||
span!(guard, "Apply pushback");
|
||||
job.cpu_stats.measure(ParMode::Rayon);
|
||||
let metrics = (
|
||||
&entities,
|
||||
&positions,
|
||||
@ -776,13 +777,10 @@ impl<'a> System<'a> for Sys {
|
||||
land_on_grounds_a
|
||||
});
|
||||
drop(guard);
|
||||
job.cpu_stats.measure(ParMode::Single);
|
||||
|
||||
land_on_grounds.into_iter().for_each(|(entity, vel)| {
|
||||
event_emitter.emit(ServerEvent::LandOnGround { entity, vel: vel.0 });
|
||||
});
|
||||
sys_metrics.phys_ns.store(
|
||||
start_time.elapsed().as_nanos() as u64,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,16 +5,15 @@ use common::{
|
||||
Stats, Vel,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
resources::DeltaTime,
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::UidAllocator,
|
||||
util::Dir,
|
||||
GroupTarget,
|
||||
};
|
||||
use specs::{
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage,
|
||||
System, SystemData, World, WriteStorage,
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData,
|
||||
World, WriteStorage,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
@ -24,7 +23,6 @@ pub struct ReadData<'a> {
|
||||
dt: Read<'a, DeltaTime>,
|
||||
uid_allocator: Read<'a, UidAllocator>,
|
||||
server_bus: Read<'a, EventBus<ServerEvent>>,
|
||||
metrics: ReadExpect<'a, SysMetrics>,
|
||||
positions: ReadStorage<'a, Pos>,
|
||||
physics_states: ReadStorage<'a, PhysicsState>,
|
||||
velocities: ReadStorage<'a, Vel>,
|
||||
@ -35,6 +33,7 @@ pub struct ReadData<'a> {
|
||||
}
|
||||
|
||||
/// This system is responsible for handling projectile effect triggers
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
@ -43,9 +42,11 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Projectile>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (read_data, mut orientations, mut projectiles): Self::SystemData) {
|
||||
let start_time = std::time::Instant::now();
|
||||
span!(_guard, "run", "projectile::Sys::run");
|
||||
const NAME: &'static str = "projectile";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(_job: &mut Job<Self>, (read_data, mut orientations, mut projectiles): Self::SystemData) {
|
||||
let mut server_emitter = read_data.server_bus.emitter();
|
||||
|
||||
// Attacks
|
||||
@ -204,9 +205,5 @@ impl<'a> System<'a> for Sys {
|
||||
.checked_sub(Duration::from_secs_f32(read_data.dt.0))
|
||||
.unwrap_or_default();
|
||||
}
|
||||
read_data.metrics.projectile_ns.store(
|
||||
start_time.elapsed().as_nanos() as u64,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,13 +6,14 @@ use common::{
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::{DeltaTime, Time},
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::{Uid, UidAllocator},
|
||||
util::Dir,
|
||||
GroupTarget,
|
||||
};
|
||||
use specs::{
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, System,
|
||||
SystemData, World, WriteStorage,
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData,
|
||||
World, WriteStorage,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
@ -39,6 +40,7 @@ pub struct ReadData<'a> {
|
||||
|
||||
/// This system is responsible for handling accepted inputs like moving or
|
||||
/// attacking
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
@ -47,7 +49,14 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, ShockwaveHitEntities>,
|
||||
);
|
||||
|
||||
fn run(&mut self, (read_data, mut shockwaves, mut shockwave_hit_lists): Self::SystemData) {
|
||||
const NAME: &'static str = "shockwave";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
_job: &mut Job<Self>,
|
||||
(read_data, mut shockwaves, mut shockwave_hit_lists): Self::SystemData,
|
||||
) {
|
||||
let mut server_emitter = read_data.server_bus.emitter();
|
||||
|
||||
let time = read_data.time.0;
|
||||
|
@ -5,16 +5,14 @@ use common::{
|
||||
PoiseChange, PoiseSource, Pos, Stats,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
outcome::Outcome,
|
||||
resources::{DeltaTime, Time},
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::Uid,
|
||||
};
|
||||
use hashbrown::HashSet;
|
||||
use specs::{
|
||||
shred::ResourceId, Entities, Join, Read, ReadExpect, ReadStorage, System, SystemData, World,
|
||||
Write, WriteStorage,
|
||||
shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData, World, Write, WriteStorage,
|
||||
};
|
||||
use vek::Vec3;
|
||||
|
||||
@ -28,7 +26,6 @@ pub struct ReadData<'a> {
|
||||
dt: Read<'a, DeltaTime>,
|
||||
time: Read<'a, Time>,
|
||||
server_bus: Read<'a, EventBus<ServerEvent>>,
|
||||
metrics: ReadExpect<'a, SysMetrics>,
|
||||
positions: ReadStorage<'a, Pos>,
|
||||
uids: ReadStorage<'a, Uid>,
|
||||
bodies: ReadStorage<'a, Body>,
|
||||
@ -36,6 +33,7 @@ pub struct ReadData<'a> {
|
||||
}
|
||||
|
||||
/// This system kills players, levels them up, and regenerates energy.
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
@ -49,8 +47,12 @@ impl<'a> System<'a> for Sys {
|
||||
Write<'a, Vec<Outcome>>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "stats";
|
||||
const ORIGIN: Origin = Origin::Common;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
read_data,
|
||||
mut stats,
|
||||
@ -61,8 +63,6 @@ impl<'a> System<'a> for Sys {
|
||||
mut outcomes,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
let start_time = std::time::Instant::now();
|
||||
span!(_guard, "run", "stats::Sys::run");
|
||||
let mut server_event_emitter = read_data.server_bus.emitter();
|
||||
let dt = read_data.dt.0;
|
||||
|
||||
@ -266,10 +266,5 @@ impl<'a> System<'a> for Sys {
|
||||
combo.reset();
|
||||
}
|
||||
}
|
||||
|
||||
read_data.metrics.stats_ns.store(
|
||||
start_time.elapsed().as_nanos() as u64,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ use common::{
|
||||
recipe::default_recipe_book,
|
||||
resources::TimeOfDay,
|
||||
rtsim::RtSimEntity,
|
||||
system::run_now,
|
||||
terrain::TerrainChunkSize,
|
||||
vol::{ReadVol, RectVolSize},
|
||||
};
|
||||
@ -78,7 +79,7 @@ use common_net::{
|
||||
use common_sys::plugin::PluginMgr;
|
||||
use common_sys::{plugin::memory_manager::EcsWorld, state::State};
|
||||
use hashbrown::HashMap;
|
||||
use metrics::{PhysicsMetrics, PlayerMetrics, StateTickMetrics, TickMetrics};
|
||||
use metrics::{EcsSystemMetrics, PhysicsMetrics, PlayerMetrics, TickMetrics};
|
||||
use network::{Network, Pid, ProtocolAddr};
|
||||
use persistence::{
|
||||
character_loader::{CharacterLoader, CharacterLoaderResponseKind},
|
||||
@ -87,11 +88,11 @@ use persistence::{
|
||||
use plugin_api::Uid;
|
||||
use prometheus::Registry;
|
||||
use prometheus_hyper::Server as PrometheusServer;
|
||||
use specs::{join::Join, Builder, Entity as EcsEntity, RunNow, SystemData, WorldExt};
|
||||
use specs::{join::Join, Builder, Entity as EcsEntity, SystemData, WorldExt};
|
||||
use std::{
|
||||
i32,
|
||||
ops::{Deref, DerefMut},
|
||||
sync::{atomic::Ordering, Arc},
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
#[cfg(not(feature = "worldgen"))]
|
||||
@ -117,6 +118,10 @@ struct SpawnPoint(Vec3<f32>);
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct Tick(u64);
|
||||
|
||||
// Start of Tick, used for metrics
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TickStart(Instant);
|
||||
|
||||
pub struct Server {
|
||||
state: State,
|
||||
world: Arc<World>,
|
||||
@ -128,9 +133,6 @@ pub struct Server {
|
||||
runtime: Arc<Runtime>,
|
||||
|
||||
metrics_shutdown: Arc<Notify>,
|
||||
tick_metrics: TickMetrics,
|
||||
state_tick_metrics: StateTickMetrics,
|
||||
physics_metrics: PhysicsMetrics,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
@ -158,10 +160,13 @@ impl Server {
|
||||
panic!("Migration error: {:?}", e);
|
||||
}
|
||||
|
||||
let (chunk_gen_metrics, registry_chunk) = metrics::ChunkGenMetrics::new().unwrap();
|
||||
let (network_request_metrics, registry_network) =
|
||||
metrics::NetworkRequestMetrics::new().unwrap();
|
||||
let (player_metrics, registry_player) = metrics::PlayerMetrics::new().unwrap();
|
||||
let registry = Arc::new(Registry::new());
|
||||
let chunk_gen_metrics = metrics::ChunkGenMetrics::new(®istry).unwrap();
|
||||
let network_request_metrics = metrics::NetworkRequestMetrics::new(®istry).unwrap();
|
||||
let player_metrics = metrics::PlayerMetrics::new(®istry).unwrap();
|
||||
let ecs_system_metrics = EcsSystemMetrics::new(®istry).unwrap();
|
||||
let tick_metrics = TickMetrics::new(®istry).unwrap();
|
||||
let physics_metrics = PhysicsMetrics::new(®istry).unwrap();
|
||||
|
||||
let mut state = State::server();
|
||||
state.ecs_mut().insert(settings.clone());
|
||||
@ -174,8 +179,12 @@ impl Server {
|
||||
.ecs_mut()
|
||||
.insert(LoginProvider::new(settings.auth_server_address.clone()));
|
||||
state.ecs_mut().insert(Tick(0));
|
||||
state.ecs_mut().insert(TickStart(Instant::now()));
|
||||
state.ecs_mut().insert(network_request_metrics);
|
||||
state.ecs_mut().insert(player_metrics);
|
||||
state.ecs_mut().insert(ecs_system_metrics);
|
||||
state.ecs_mut().insert(tick_metrics);
|
||||
state.ecs_mut().insert(physics_metrics);
|
||||
state
|
||||
.ecs_mut()
|
||||
.insert(ChunkGenerator::new(chunk_gen_metrics));
|
||||
@ -195,23 +204,6 @@ impl Server {
|
||||
.ecs_mut()
|
||||
.insert(CharacterLoader::new(&persistence_db_dir)?);
|
||||
|
||||
// System timers for performance monitoring
|
||||
state.ecs_mut().insert(sys::EntitySyncTimer::default());
|
||||
state.ecs_mut().insert(sys::GeneralMsgTimer::default());
|
||||
state.ecs_mut().insert(sys::PingMsgTimer::default());
|
||||
state
|
||||
.ecs_mut()
|
||||
.insert(sys::CharacterScreenMsgTimer::default());
|
||||
state.ecs_mut().insert(sys::InGameMsgTimer::default());
|
||||
state.ecs_mut().insert(sys::SentinelTimer::default());
|
||||
state.ecs_mut().insert(sys::SubscriptionTimer::default());
|
||||
state.ecs_mut().insert(sys::TerrainSyncTimer::default());
|
||||
state.ecs_mut().insert(sys::TerrainTimer::default());
|
||||
state.ecs_mut().insert(sys::WaypointTimer::default());
|
||||
state.ecs_mut().insert(sys::InviteTimeoutTimer::default());
|
||||
state.ecs_mut().insert(sys::PersistenceTimer::default());
|
||||
state.ecs_mut().insert(sys::AgentTimer::default());
|
||||
|
||||
// System schedulers to control execution of systems
|
||||
state
|
||||
.ecs_mut()
|
||||
@ -356,20 +348,6 @@ impl Server {
|
||||
|
||||
state.ecs_mut().insert(DeletedEntities::default());
|
||||
|
||||
// register all metrics submodules here
|
||||
let (tick_metrics, registry_tick) =
|
||||
TickMetrics::new().expect("Failed to initialize server tick metrics submodule.");
|
||||
let (state_tick_metrics, registry_state) = StateTickMetrics::new().unwrap();
|
||||
let (physics_metrics, registry_physics) = PhysicsMetrics::new().unwrap();
|
||||
|
||||
let registry = Arc::new(Registry::new());
|
||||
registry_chunk(®istry).expect("failed to register chunk gen metrics");
|
||||
registry_network(®istry).expect("failed to register network request metrics");
|
||||
registry_player(®istry).expect("failed to register player metrics");
|
||||
registry_tick(®istry).expect("failed to register tick metrics");
|
||||
registry_state(®istry).expect("failed to register state metrics");
|
||||
registry_physics(®istry).expect("failed to register state metrics");
|
||||
|
||||
let network = Network::new_with_registry(Pid::new(), &runtime, ®istry);
|
||||
let metrics_shutdown = Arc::new(Notify::new());
|
||||
let metrics_shutdown_clone = Arc::clone(&metrics_shutdown);
|
||||
@ -402,9 +380,6 @@ impl Server {
|
||||
runtime,
|
||||
|
||||
metrics_shutdown,
|
||||
tick_metrics,
|
||||
state_tick_metrics,
|
||||
physics_metrics,
|
||||
};
|
||||
|
||||
debug!(?settings, "created veloren server with");
|
||||
@ -472,6 +447,8 @@ impl Server {
|
||||
/// the given duration.
|
||||
pub fn tick(&mut self, _input: Input, dt: Duration) -> Result<Vec<Event>, Error> {
|
||||
self.state.ecs().write_resource::<Tick>().0 += 1;
|
||||
self.state.ecs().write_resource::<TickStart>().0 = Instant::now();
|
||||
|
||||
// This tick function is the centre of the Veloren universe. Most server-side
|
||||
// things are managed from here, and as such it's important that it
|
||||
// stays organised. Please consult the core developers before making
|
||||
@ -510,12 +487,12 @@ impl Server {
|
||||
// Run message receiving sys before the systems in common for decreased latency
|
||||
// (e.g. run before controller system)
|
||||
//TODO: run in parallel
|
||||
sys::msg::general::Sys.run_now(&self.state.ecs());
|
||||
run_now::<sys::msg::general::Sys>(&self.state.ecs());
|
||||
self.register_run();
|
||||
sys::msg::character_screen::Sys.run_now(&self.state.ecs());
|
||||
sys::msg::in_game::Sys.run_now(&self.state.ecs());
|
||||
sys::msg::ping::Sys.run_now(&self.state.ecs());
|
||||
sys::agent::Sys.run_now(&self.state.ecs());
|
||||
run_now::<sys::msg::character_screen::Sys>(&self.state.ecs());
|
||||
run_now::<sys::msg::in_game::Sys>(&self.state.ecs());
|
||||
run_now::<sys::msg::ping::Sys>(&self.state.ecs());
|
||||
run_now::<sys::agent::Sys>(&self.state.ecs());
|
||||
|
||||
let before_state_tick = Instant::now();
|
||||
|
||||
@ -704,211 +681,29 @@ impl Server {
|
||||
let end_of_server_tick = Instant::now();
|
||||
|
||||
// 8) Update Metrics
|
||||
// Get system timing info
|
||||
let agent_nanos = self.state.ecs().read_resource::<sys::AgentTimer>().nanos as i64;
|
||||
let entity_sync_nanos = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<sys::EntitySyncTimer>()
|
||||
.nanos as i64;
|
||||
let message_nanos = {
|
||||
let state = self.state.ecs();
|
||||
(state.read_resource::<sys::GeneralMsgTimer>().nanos
|
||||
+ state.read_resource::<sys::PingMsgTimer>().nanos
|
||||
+ state.read_resource::<sys::CharacterScreenMsgTimer>().nanos
|
||||
+ state.read_resource::<sys::InGameMsgTimer>().nanos) as i64
|
||||
};
|
||||
let sentinel_nanos = self.state.ecs().read_resource::<sys::SentinelTimer>().nanos as i64;
|
||||
let subscription_nanos = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<sys::SubscriptionTimer>()
|
||||
.nanos as i64;
|
||||
let terrain_sync_nanos = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<sys::TerrainSyncTimer>()
|
||||
.nanos as i64;
|
||||
let terrain_nanos = self.state.ecs().read_resource::<sys::TerrainTimer>().nanos as i64;
|
||||
let waypoint_nanos = self.state.ecs().read_resource::<sys::WaypointTimer>().nanos as i64;
|
||||
let invite_timeout_nanos = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<sys::InviteTimeoutTimer>()
|
||||
.nanos as i64;
|
||||
let stats_persistence_nanos = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<sys::PersistenceTimer>()
|
||||
.nanos as i64;
|
||||
let total_sys_ran_in_dispatcher_nanos =
|
||||
terrain_nanos + waypoint_nanos + invite_timeout_nanos + stats_persistence_nanos;
|
||||
run_now::<sys::metrics::Sys>(&self.state.ecs());
|
||||
|
||||
// Report timing info
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["new connections"])
|
||||
.set((before_message_system - before_new_connections).as_nanos() as i64);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["state tick"])
|
||||
.set(
|
||||
(before_handle_events - before_state_tick).as_nanos() as i64
|
||||
- total_sys_ran_in_dispatcher_nanos,
|
||||
);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["handle server events"])
|
||||
.set((before_update_terrain_and_regions - before_handle_events).as_nanos() as i64);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["update terrain and region map"])
|
||||
.set((before_sync - before_update_terrain_and_regions).as_nanos() as i64);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["world tick"])
|
||||
.set((before_entity_cleanup - before_world_tick).as_nanos() as i64);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["entity cleanup"])
|
||||
.set((before_persistence_updates - before_entity_cleanup).as_nanos() as i64);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["persistence_updates"])
|
||||
.set((end_of_server_tick - before_persistence_updates).as_nanos() as i64);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["entity sync"])
|
||||
.set(entity_sync_nanos);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["message"])
|
||||
.set(message_nanos);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["sentinel"])
|
||||
.set(sentinel_nanos);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["subscription"])
|
||||
.set(subscription_nanos);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["terrain sync"])
|
||||
.set(terrain_sync_nanos);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["terrain"])
|
||||
.set(terrain_nanos);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["waypoint"])
|
||||
.set(waypoint_nanos);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["invite timeout"])
|
||||
.set(invite_timeout_nanos);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["persistence:stats"])
|
||||
.set(stats_persistence_nanos);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["agent"])
|
||||
.set(agent_nanos);
|
||||
|
||||
//detailed state metrics
|
||||
{
|
||||
let res = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<common::metrics::SysMetrics>();
|
||||
let c = &self.state_tick_metrics.state_tick_time_count;
|
||||
let agent_ns = res.agent_ns.load(Ordering::Relaxed);
|
||||
let mount_ns = res.mount_ns.load(Ordering::Relaxed);
|
||||
let controller_ns = res.controller_ns.load(Ordering::Relaxed);
|
||||
let character_behavior_ns = res.character_behavior_ns.load(Ordering::Relaxed);
|
||||
let stats_ns = res.stats_ns.load(Ordering::Relaxed);
|
||||
let phys_ns = res.phys_ns.load(Ordering::Relaxed);
|
||||
let projectile_ns = res.projectile_ns.load(Ordering::Relaxed);
|
||||
let melee_ns = res.melee_ns.load(Ordering::Relaxed);
|
||||
// Report timing info
|
||||
let tick_metrics = self.state.ecs().read_resource::<metrics::TickMetrics>();
|
||||
|
||||
c.with_label_values(&[sys::AGENT_SYS]).inc_by(agent_ns);
|
||||
c.with_label_values(&[common_sys::MOUNT_SYS])
|
||||
.inc_by(mount_ns);
|
||||
c.with_label_values(&[common_sys::CONTROLLER_SYS])
|
||||
.inc_by(controller_ns);
|
||||
c.with_label_values(&[common_sys::CHARACTER_BEHAVIOR_SYS])
|
||||
.inc_by(character_behavior_ns);
|
||||
c.with_label_values(&[common_sys::STATS_SYS])
|
||||
.inc_by(stats_ns);
|
||||
c.with_label_values(&[common_sys::PHYS_SYS]).inc_by(phys_ns);
|
||||
c.with_label_values(&[common_sys::PROJECTILE_SYS])
|
||||
.inc_by(projectile_ns);
|
||||
c.with_label_values(&[common_sys::MELEE_SYS])
|
||||
.inc_by(melee_ns);
|
||||
|
||||
const NANOSEC_PER_SEC: f64 = Duration::from_secs(1).as_nanos() as f64;
|
||||
let h = &self.state_tick_metrics.state_tick_time_hist;
|
||||
h.with_label_values(&[sys::AGENT_SYS])
|
||||
.observe(agent_ns as f64 / NANOSEC_PER_SEC);
|
||||
h.with_label_values(&[common_sys::MOUNT_SYS])
|
||||
.observe(mount_ns as f64 / NANOSEC_PER_SEC);
|
||||
h.with_label_values(&[common_sys::CONTROLLER_SYS])
|
||||
.observe(controller_ns as f64 / NANOSEC_PER_SEC);
|
||||
h.with_label_values(&[common_sys::CHARACTER_BEHAVIOR_SYS])
|
||||
.observe(character_behavior_ns as f64 / NANOSEC_PER_SEC);
|
||||
h.with_label_values(&[common_sys::STATS_SYS])
|
||||
.observe(stats_ns as f64 / NANOSEC_PER_SEC);
|
||||
h.with_label_values(&[common_sys::PHYS_SYS])
|
||||
.observe(phys_ns as f64 / NANOSEC_PER_SEC);
|
||||
h.with_label_values(&[common_sys::PROJECTILE_SYS])
|
||||
.observe(projectile_ns as f64 / NANOSEC_PER_SEC);
|
||||
h.with_label_values(&[common_sys::MELEE_SYS])
|
||||
.observe(melee_ns as f64 / NANOSEC_PER_SEC);
|
||||
let tt = &tick_metrics.tick_time;
|
||||
tt.with_label_values(&["new connections"])
|
||||
.set((before_message_system - before_new_connections).as_nanos() as i64);
|
||||
tt.with_label_values(&["handle server events"])
|
||||
.set((before_update_terrain_and_regions - before_handle_events).as_nanos() as i64);
|
||||
tt.with_label_values(&["update terrain and region map"])
|
||||
.set((before_sync - before_update_terrain_and_regions).as_nanos() as i64);
|
||||
tt.with_label_values(&["state"])
|
||||
.set((before_handle_events - before_state_tick).as_nanos() as i64);
|
||||
tt.with_label_values(&["world tick"])
|
||||
.set((before_entity_cleanup - before_world_tick).as_nanos() as i64);
|
||||
tt.with_label_values(&["entity cleanup"])
|
||||
.set((before_persistence_updates - before_entity_cleanup).as_nanos() as i64);
|
||||
tt.with_label_values(&["persistence_updates"])
|
||||
.set((end_of_server_tick - before_persistence_updates).as_nanos() as i64);
|
||||
}
|
||||
|
||||
//detailed physics metrics
|
||||
{
|
||||
let res = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<common::metrics::PhysicsMetrics>();
|
||||
|
||||
self.physics_metrics
|
||||
.entity_entity_collision_checks_count
|
||||
.inc_by(res.entity_entity_collision_checks);
|
||||
self.physics_metrics
|
||||
.entity_entity_collisions_count
|
||||
.inc_by(res.entity_entity_collisions);
|
||||
}
|
||||
|
||||
// Report other info
|
||||
self.tick_metrics
|
||||
.time_of_day
|
||||
.set(self.state.ecs().read_resource::<TimeOfDay>().0);
|
||||
if self.tick_metrics.is_100th_tick() {
|
||||
let mut chonk_cnt = 0;
|
||||
let mut group_cnt = 0;
|
||||
let chunk_cnt = self.state.terrain().iter().fold(0, |a, (_, c)| {
|
||||
chonk_cnt += 1;
|
||||
group_cnt += c.sub_chunk_groups();
|
||||
a + c.sub_chunks_len()
|
||||
});
|
||||
self.tick_metrics.chonks_count.set(chonk_cnt as i64);
|
||||
self.tick_metrics.chunks_count.set(chunk_cnt as i64);
|
||||
self.tick_metrics.chunk_groups_count.set(group_cnt as i64);
|
||||
|
||||
let entity_count = self.state.ecs().entities().join().count();
|
||||
self.tick_metrics.entity_count.set(entity_count as i64);
|
||||
}
|
||||
//self.metrics.entity_count.set(self.state.);
|
||||
self.tick_metrics
|
||||
.tick_time
|
||||
.with_label_values(&["metrics"])
|
||||
.set(end_of_server_tick.elapsed().as_nanos() as i64);
|
||||
self.tick_metrics.tick();
|
||||
|
||||
// 9) Finish the tick, pass control back to the frontend.
|
||||
|
||||
Ok(frontend_events)
|
||||
|
@ -1,29 +1,27 @@
|
||||
use prometheus::{
|
||||
Gauge, HistogramOpts, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec, Opts,
|
||||
Registry,
|
||||
Gauge, GaugeVec, HistogramOpts, HistogramVec, IntCounter, IntCounterVec, IntGauge, IntGaugeVec,
|
||||
Opts, Registry,
|
||||
};
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
error::Error,
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc,
|
||||
},
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
type RegistryFn = Box<dyn FnOnce(&Registry) -> Result<(), prometheus::Error>>;
|
||||
|
||||
pub struct PhysicsMetrics {
|
||||
pub entity_entity_collision_checks_count: IntCounter,
|
||||
pub entity_entity_collisions_count: IntCounter,
|
||||
}
|
||||
|
||||
pub struct StateTickMetrics {
|
||||
// Counter will only give us granularity on pool speed (2s?) for actuall spike detection we
|
||||
pub struct EcsSystemMetrics {
|
||||
// Gauges give us detailed information for random ticks
|
||||
pub system_start_time: IntGaugeVec,
|
||||
pub system_length_time: IntGaugeVec,
|
||||
pub system_thread_avg: GaugeVec,
|
||||
// Counter will only give us granularity on pool speed (2s?) for actual spike detection we
|
||||
// need the Historgram
|
||||
pub state_tick_time_hist: HistogramVec,
|
||||
pub state_tick_time_count: IntCounterVec,
|
||||
pub system_length_hist: HistogramVec,
|
||||
pub system_length_count: IntCounterVec,
|
||||
}
|
||||
|
||||
pub struct PlayerMetrics {
|
||||
@ -54,11 +52,10 @@ pub struct TickMetrics {
|
||||
pub start_time: IntGauge,
|
||||
pub time_of_day: Gauge,
|
||||
pub light_count: IntGauge,
|
||||
tick: Arc<AtomicU64>,
|
||||
}
|
||||
|
||||
impl PhysicsMetrics {
|
||||
pub fn new() -> Result<(Self, RegistryFn), prometheus::Error> {
|
||||
pub fn new(registry: &Registry) -> Result<Self, prometheus::Error> {
|
||||
let entity_entity_collision_checks_count = IntCounter::with_opts(Opts::new(
|
||||
"entity_entity_collision_checks_count",
|
||||
"shows the number of collision checks",
|
||||
@ -68,28 +65,18 @@ impl PhysicsMetrics {
|
||||
"shows the number of actual collisions detected",
|
||||
))?;
|
||||
|
||||
let entity_entity_collision_checks_count_clone =
|
||||
entity_entity_collision_checks_count.clone();
|
||||
let entity_entity_collisions_count_clone = entity_entity_collisions_count.clone();
|
||||
registry.register(Box::new(entity_entity_collision_checks_count.clone()))?;
|
||||
registry.register(Box::new(entity_entity_collisions_count.clone()))?;
|
||||
|
||||
let f = |registry: &Registry| {
|
||||
registry.register(Box::new(entity_entity_collision_checks_count_clone))?;
|
||||
registry.register(Box::new(entity_entity_collisions_count_clone))?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
entity_entity_collision_checks_count,
|
||||
entity_entity_collisions_count,
|
||||
},
|
||||
Box::new(f),
|
||||
))
|
||||
Ok(Self {
|
||||
entity_entity_collision_checks_count,
|
||||
entity_entity_collisions_count,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl StateTickMetrics {
|
||||
pub fn new() -> Result<(Self, RegistryFn), prometheus::Error> {
|
||||
impl EcsSystemMetrics {
|
||||
pub fn new(registry: &Registry) -> Result<Self, prometheus::Error> {
|
||||
let bucket = vec![
|
||||
Duration::from_micros(1).as_secs_f64(),
|
||||
Duration::from_micros(10).as_secs_f64(),
|
||||
@ -104,43 +91,58 @@ impl StateTickMetrics {
|
||||
Duration::from_millis(50).as_secs_f64(),
|
||||
Duration::from_millis(100).as_secs_f64(),
|
||||
];
|
||||
let state_tick_time_hist = HistogramVec::new(
|
||||
let system_length_hist = HistogramVec::new(
|
||||
HistogramOpts::new(
|
||||
"state_tick_time_hist",
|
||||
"shows the number of clients joined to the server",
|
||||
"system_length_hist",
|
||||
"shows the detailed time in ns inside each ECS system as histogram",
|
||||
)
|
||||
.buckets(bucket),
|
||||
&["system"],
|
||||
)?;
|
||||
let state_tick_time_count = IntCounterVec::new(
|
||||
let system_length_count = IntCounterVec::new(
|
||||
Opts::new(
|
||||
"state_tick_time_count",
|
||||
"shows the detailed time inside the `state_tick` for each system",
|
||||
"system_length_count",
|
||||
"shows the detailed time in ns inside each ECS system",
|
||||
),
|
||||
&["system"],
|
||||
)?;
|
||||
let system_start_time = IntGaugeVec::new(
|
||||
Opts::new(
|
||||
"system_start_time",
|
||||
"start relative to tick start in ns required per ECS system",
|
||||
),
|
||||
&["system"],
|
||||
)?;
|
||||
let system_length_time = IntGaugeVec::new(
|
||||
Opts::new("system_length_time", "time in ns required per ECS system"),
|
||||
&["system"],
|
||||
)?;
|
||||
let system_thread_avg = GaugeVec::new(
|
||||
Opts::new(
|
||||
"system_thread_avg",
|
||||
"average threads used by the ECS system",
|
||||
),
|
||||
&["system"],
|
||||
)?;
|
||||
|
||||
let state_tick_time_hist_clone = state_tick_time_hist.clone();
|
||||
let state_tick_time_count_clone = state_tick_time_count.clone();
|
||||
registry.register(Box::new(system_length_hist.clone()))?;
|
||||
registry.register(Box::new(system_length_count.clone()))?;
|
||||
registry.register(Box::new(system_start_time.clone()))?;
|
||||
registry.register(Box::new(system_length_time.clone()))?;
|
||||
registry.register(Box::new(system_thread_avg.clone()))?;
|
||||
|
||||
let f = |registry: &Registry| {
|
||||
registry.register(Box::new(state_tick_time_hist_clone))?;
|
||||
registry.register(Box::new(state_tick_time_count_clone))?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
state_tick_time_hist,
|
||||
state_tick_time_count,
|
||||
},
|
||||
Box::new(f),
|
||||
))
|
||||
Ok(Self {
|
||||
system_length_hist,
|
||||
system_length_count,
|
||||
system_start_time,
|
||||
system_length_time,
|
||||
system_thread_avg,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayerMetrics {
|
||||
pub fn new() -> Result<(Self, RegistryFn), prometheus::Error> {
|
||||
pub fn new(registry: &Registry) -> Result<Self, prometheus::Error> {
|
||||
let clients_connected = IntCounter::with_opts(Opts::new(
|
||||
"clients_connected",
|
||||
"shows the number of clients joined to the server",
|
||||
@ -158,30 +160,20 @@ impl PlayerMetrics {
|
||||
&["reason"],
|
||||
)?;
|
||||
|
||||
let clients_connected_clone = clients_connected.clone();
|
||||
let players_connected_clone = players_connected.clone();
|
||||
let clients_disconnected_clone = clients_disconnected.clone();
|
||||
registry.register(Box::new(clients_connected.clone()))?;
|
||||
registry.register(Box::new(players_connected.clone()))?;
|
||||
registry.register(Box::new(clients_disconnected.clone()))?;
|
||||
|
||||
let f = |registry: &Registry| {
|
||||
registry.register(Box::new(clients_connected_clone))?;
|
||||
registry.register(Box::new(players_connected_clone))?;
|
||||
registry.register(Box::new(clients_disconnected_clone))?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
clients_connected,
|
||||
players_connected,
|
||||
clients_disconnected,
|
||||
},
|
||||
Box::new(f),
|
||||
))
|
||||
Ok(Self {
|
||||
clients_connected,
|
||||
players_connected,
|
||||
clients_disconnected,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkRequestMetrics {
|
||||
pub fn new() -> Result<(Self, RegistryFn), prometheus::Error> {
|
||||
pub fn new(registry: &Registry) -> Result<Self, prometheus::Error> {
|
||||
let chunks_request_dropped = IntCounter::with_opts(Opts::new(
|
||||
"chunks_request_dropped",
|
||||
"number of all chunk request dropped, e.g because the player was to far away",
|
||||
@ -195,30 +187,20 @@ impl NetworkRequestMetrics {
|
||||
"number of all chunks that were requested and needs to be generated",
|
||||
))?;
|
||||
|
||||
let chunks_request_dropped_clone = chunks_request_dropped.clone();
|
||||
let chunks_served_from_memory_clone = chunks_served_from_memory.clone();
|
||||
let chunks_generation_triggered_clone = chunks_generation_triggered.clone();
|
||||
registry.register(Box::new(chunks_request_dropped.clone()))?;
|
||||
registry.register(Box::new(chunks_served_from_memory.clone()))?;
|
||||
registry.register(Box::new(chunks_generation_triggered.clone()))?;
|
||||
|
||||
let f = |registry: &Registry| {
|
||||
registry.register(Box::new(chunks_request_dropped_clone))?;
|
||||
registry.register(Box::new(chunks_served_from_memory_clone))?;
|
||||
registry.register(Box::new(chunks_generation_triggered_clone))?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
chunks_request_dropped,
|
||||
chunks_served_from_memory,
|
||||
chunks_generation_triggered,
|
||||
},
|
||||
Box::new(f),
|
||||
))
|
||||
Ok(Self {
|
||||
chunks_request_dropped,
|
||||
chunks_served_from_memory,
|
||||
chunks_generation_triggered,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ChunkGenMetrics {
|
||||
pub fn new() -> Result<(Self, RegistryFn), prometheus::Error> {
|
||||
pub fn new(registry: &Registry) -> Result<Self, prometheus::Error> {
|
||||
let chunks_requested = IntCounter::with_opts(Opts::new(
|
||||
"chunks_requested",
|
||||
"number of all chunks requested on the server",
|
||||
@ -232,30 +214,20 @@ impl ChunkGenMetrics {
|
||||
"number of all canceled chunks on the server",
|
||||
))?;
|
||||
|
||||
let chunks_requested_clone = chunks_requested.clone();
|
||||
let chunks_served_clone = chunks_served.clone();
|
||||
let chunks_canceled_clone = chunks_canceled.clone();
|
||||
registry.register(Box::new(chunks_requested.clone()))?;
|
||||
registry.register(Box::new(chunks_served.clone()))?;
|
||||
registry.register(Box::new(chunks_canceled.clone()))?;
|
||||
|
||||
let f = |registry: &Registry| {
|
||||
registry.register(Box::new(chunks_requested_clone))?;
|
||||
registry.register(Box::new(chunks_served_clone))?;
|
||||
registry.register(Box::new(chunks_canceled_clone))?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
chunks_requested,
|
||||
chunks_served,
|
||||
chunks_canceled,
|
||||
},
|
||||
Box::new(f),
|
||||
))
|
||||
Ok(Self {
|
||||
chunks_requested,
|
||||
chunks_served,
|
||||
chunks_canceled,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TickMetrics {
|
||||
pub fn new() -> Result<(Self, RegistryFn), Box<dyn Error>> {
|
||||
pub fn new(registry: &Registry) -> Result<Self, Box<dyn Error>> {
|
||||
let chonks_count = IntGauge::with_opts(Opts::new(
|
||||
"chonks_count",
|
||||
"number of all chonks currently active on the server",
|
||||
@ -296,48 +268,26 @@ impl TickMetrics {
|
||||
.expect("Time went backwards");
|
||||
start_time.set(since_the_epoch.as_secs().try_into()?);
|
||||
|
||||
let chonks_count_clone = chonks_count.clone();
|
||||
let chunks_count_clone = chunks_count.clone();
|
||||
let chunk_groups_count_clone = chunk_groups_count.clone();
|
||||
let entity_count_clone = entity_count.clone();
|
||||
let build_info_clone = build_info.clone();
|
||||
let start_time_clone = start_time.clone();
|
||||
let time_of_day_clone = time_of_day.clone();
|
||||
let light_count_clone = light_count.clone();
|
||||
let tick_time_clone = tick_time.clone();
|
||||
let tick = Arc::new(AtomicU64::new(0));
|
||||
registry.register(Box::new(chonks_count.clone()))?;
|
||||
registry.register(Box::new(chunks_count.clone()))?;
|
||||
registry.register(Box::new(chunk_groups_count.clone()))?;
|
||||
registry.register(Box::new(entity_count.clone()))?;
|
||||
registry.register(Box::new(build_info.clone()))?;
|
||||
registry.register(Box::new(start_time.clone()))?;
|
||||
registry.register(Box::new(time_of_day.clone()))?;
|
||||
registry.register(Box::new(light_count.clone()))?;
|
||||
registry.register(Box::new(tick_time.clone()))?;
|
||||
|
||||
let f = |registry: &Registry| {
|
||||
registry.register(Box::new(chonks_count_clone))?;
|
||||
registry.register(Box::new(chunks_count_clone))?;
|
||||
registry.register(Box::new(chunk_groups_count_clone))?;
|
||||
registry.register(Box::new(entity_count_clone))?;
|
||||
registry.register(Box::new(build_info_clone))?;
|
||||
registry.register(Box::new(start_time_clone))?;
|
||||
registry.register(Box::new(time_of_day_clone))?;
|
||||
registry.register(Box::new(light_count_clone))?;
|
||||
registry.register(Box::new(tick_time_clone))?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
chonks_count,
|
||||
chunks_count,
|
||||
chunk_groups_count,
|
||||
entity_count,
|
||||
tick_time,
|
||||
build_info,
|
||||
start_time,
|
||||
time_of_day,
|
||||
light_count,
|
||||
tick,
|
||||
},
|
||||
Box::new(f),
|
||||
))
|
||||
Ok(Self {
|
||||
chonks_count,
|
||||
chunks_count,
|
||||
chunk_groups_count,
|
||||
entity_count,
|
||||
tick_time,
|
||||
build_info,
|
||||
start_time,
|
||||
time_of_day,
|
||||
light_count,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn tick(&self) { self.tick.fetch_add(1, Ordering::Relaxed); }
|
||||
|
||||
pub fn is_100th_tick(&self) -> bool { self.tick.load(Ordering::Relaxed).rem_euclid(100) == 0 }
|
||||
}
|
||||
|
@ -1,13 +1,21 @@
|
||||
use super::*;
|
||||
use common::event::{EventBus, ServerEvent};
|
||||
use specs::{Read, System, WriteExpect};
|
||||
use common::{
|
||||
event::{EventBus, ServerEvent},
|
||||
system::{Job, Origin, Phase, System},
|
||||
};
|
||||
use specs::{Read, WriteExpect};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (Read<'a, EventBus<ServerEvent>>, WriteExpect<'a, RtSim>);
|
||||
|
||||
fn run(&mut self, (_server_event_bus, mut rtsim): Self::SystemData) {
|
||||
const NAME: &'static str = "rtsim::load_chunks";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(_job: &mut Job<Self>, (_server_event_bus, mut rtsim): Self::SystemData) {
|
||||
for _chunk in std::mem::take(&mut rtsim.chunks.chunks_to_load) {
|
||||
// TODO
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use self::{chunks::Chunks, entity::Entity};
|
||||
use common::{
|
||||
comp,
|
||||
rtsim::{RtSimController, RtSimEntity, RtSimId},
|
||||
system::{dispatch, System},
|
||||
terrain::TerrainChunk,
|
||||
vol::RectRasterableVol,
|
||||
};
|
||||
@ -72,14 +73,13 @@ impl RtSim {
|
||||
}
|
||||
}
|
||||
|
||||
const LOAD_CHUNK_SYS: &str = "rtsim_load_chunk_sys";
|
||||
const UNLOAD_CHUNK_SYS: &str = "rtsim_unload_chunk_sys";
|
||||
const TICK_SYS: &str = "rtsim_tick_sys";
|
||||
|
||||
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch_builder.add(unload_chunks::Sys, UNLOAD_CHUNK_SYS, &[]);
|
||||
dispatch_builder.add(load_chunks::Sys, LOAD_CHUNK_SYS, &[UNLOAD_CHUNK_SYS]);
|
||||
dispatch_builder.add(tick::Sys, TICK_SYS, &[LOAD_CHUNK_SYS, UNLOAD_CHUNK_SYS]);
|
||||
dispatch::<unload_chunks::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<load_chunks::Sys>(dispatch_builder, &[&unload_chunks::Sys::sys_name()]);
|
||||
dispatch::<tick::Sys>(dispatch_builder, &[
|
||||
&load_chunks::Sys::sys_name(),
|
||||
&unload_chunks::Sys::sys_name(),
|
||||
]);
|
||||
}
|
||||
|
||||
pub fn init(state: &mut State, #[cfg(feature = "worldgen")] world: &world::World) {
|
||||
|
@ -6,13 +6,15 @@ use common::{
|
||||
comp::inventory::loadout_builder::LoadoutBuilder,
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::DeltaTime,
|
||||
system::{Job, Origin, Phase, System},
|
||||
terrain::TerrainGrid,
|
||||
};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteExpect, WriteStorage};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
|
||||
use std::sync::Arc;
|
||||
|
||||
const ENTITY_TICK_PERIOD: u64 = 30;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
@ -28,8 +30,12 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, comp::Agent>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "rtsim::tick";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
dt,
|
||||
server_event_bus,
|
||||
|
@ -2,10 +2,12 @@ use super::*;
|
||||
use common::{
|
||||
comp::Pos,
|
||||
event::{EventBus, ServerEvent},
|
||||
system::{Job, Origin, Phase, System},
|
||||
terrain::TerrainGrid,
|
||||
};
|
||||
use specs::{Entities, Read, ReadExpect, ReadStorage, System, WriteExpect};
|
||||
use specs::{Entities, Read, ReadExpect, ReadStorage, WriteExpect};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
@ -18,8 +20,12 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Pos>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "rtsim::unload_chunks";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
_server_event_bus,
|
||||
mut rtsim,
|
||||
|
@ -1,4 +1,3 @@
|
||||
use super::SysTimer;
|
||||
use common::{
|
||||
comp::{
|
||||
self,
|
||||
@ -16,10 +15,9 @@ use common::{
|
||||
UnresolvedChatMsg, Vel,
|
||||
},
|
||||
event::{Emitter, EventBus, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
path::TraversalConfig,
|
||||
resources::{DeltaTime, TimeOfDay},
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
terrain::{Block, TerrainGrid},
|
||||
time::DayPeriod,
|
||||
uid::{Uid, UidAllocator},
|
||||
@ -31,8 +29,8 @@ use rayon::iter::ParallelIterator;
|
||||
use specs::{
|
||||
saveload::{Marker, MarkerAllocator},
|
||||
shred::ResourceId,
|
||||
Entities, Entity as EcsEntity, Join, ParJoin, Read, ReadExpect, ReadStorage, System,
|
||||
SystemData, World, Write, WriteStorage,
|
||||
Entities, Entity as EcsEntity, Join, ParJoin, Read, ReadExpect, ReadStorage, SystemData, World,
|
||||
Write, WriteStorage,
|
||||
};
|
||||
use std::f32::consts::PI;
|
||||
use vek::*;
|
||||
@ -64,7 +62,6 @@ pub struct ReadData<'a> {
|
||||
uid_allocator: Read<'a, UidAllocator>,
|
||||
dt: Read<'a, DeltaTime>,
|
||||
group_manager: Read<'a, group::GroupManager>,
|
||||
sys_metrics: ReadExpect<'a, SysMetrics>,
|
||||
energies: ReadStorage<'a, Energy>,
|
||||
positions: ReadStorage<'a, Pos>,
|
||||
velocities: ReadStorage<'a, Vel>,
|
||||
@ -99,26 +96,26 @@ const SNEAK_COEFFICIENT: f32 = 0.25;
|
||||
const AVG_FOLLOW_DIST: f32 = 6.0;
|
||||
|
||||
/// This system will allow NPCs to modify their controller
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
ReadData<'a>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
Write<'a, EventBus<ServerEvent>>,
|
||||
WriteStorage<'a, Agent>,
|
||||
WriteStorage<'a, Controller>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "agent";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
||||
fn run(
|
||||
&mut self,
|
||||
(read_data, mut sys_timer, event_bus, mut agents, mut controllers): Self::SystemData,
|
||||
_job: &mut Job<Self>,
|
||||
(read_data, event_bus, mut agents, mut controllers): Self::SystemData,
|
||||
) {
|
||||
let start_time = std::time::Instant::now();
|
||||
span!(_guard, "run", "agent::Sys::run");
|
||||
sys_timer.start();
|
||||
|
||||
(
|
||||
&read_data.entities,
|
||||
(&read_data.energies, &read_data.healths),
|
||||
@ -423,13 +420,6 @@ impl<'a> System<'a> for Sys {
|
||||
debug_assert!(controller.inputs.look_dir.map(|e| !e.is_nan()).reduce_and());
|
||||
},
|
||||
);
|
||||
|
||||
read_data.sys_metrics.agent_ns.store(
|
||||
start_time.elapsed().as_nanos() as u64,
|
||||
std::sync::atomic::Ordering::Relaxed,
|
||||
);
|
||||
|
||||
sys_timer.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
use super::{
|
||||
sentinel::{DeletedEntities, ReadTrackers, TrackedComps},
|
||||
SysTimer,
|
||||
};
|
||||
use super::sentinel::{DeletedEntities, ReadTrackers, TrackedComps};
|
||||
use crate::{
|
||||
client::Client,
|
||||
presence::{Presence, RegionSubscription},
|
||||
@ -12,27 +9,27 @@ use common::{
|
||||
outcome::Outcome,
|
||||
region::{Event as RegionEvent, RegionMap},
|
||||
resources::TimeOfDay,
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
terrain::TerrainChunkSize,
|
||||
uid::Uid,
|
||||
vol::RectVolSize,
|
||||
};
|
||||
use common_net::{msg::ServerGeneral, sync::CompSyncPackage};
|
||||
use specs::{
|
||||
Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage,
|
||||
Entities, Entity as EcsEntity, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
/// This system will send physics updates to the client
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, Tick>,
|
||||
ReadExpect<'a, TimeOfDay>,
|
||||
ReadExpect<'a, RegionMap>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Vel>,
|
||||
@ -52,14 +49,17 @@ impl<'a> System<'a> for Sys {
|
||||
ReadTrackers<'a>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "entity_sync";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
tick,
|
||||
time_of_day,
|
||||
region_map,
|
||||
mut timer,
|
||||
uids,
|
||||
positions,
|
||||
velocities,
|
||||
@ -79,9 +79,6 @@ impl<'a> System<'a> for Sys {
|
||||
trackers,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "entity_sync::Sys::run");
|
||||
timer.start();
|
||||
|
||||
let tick = tick.0;
|
||||
// To send entity updates
|
||||
// 1. Iterate through regions
|
||||
@ -381,7 +378,5 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
tof_lazymsg.as_ref().map(|msg| client.send_prepared(&msg));
|
||||
}
|
||||
|
||||
timer.end();
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,34 @@
|
||||
use super::SysTimer;
|
||||
use crate::client::Client;
|
||||
use common::{
|
||||
comp::invite::{Invite, PendingInvites},
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::Uid,
|
||||
};
|
||||
use common_net::msg::{InviteAnswer, ServerGeneral};
|
||||
use specs::{Entities, Join, ReadStorage, System, Write, WriteStorage};
|
||||
use specs::{Entities, Join, ReadStorage, WriteStorage};
|
||||
|
||||
/// This system removes timed out invites
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
WriteStorage<'a, Invite>,
|
||||
WriteStorage<'a, PendingInvites>,
|
||||
ReadStorage<'a, Client>,
|
||||
ReadStorage<'a, Uid>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "invite_timeout";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(entities, mut invites, mut pending_invites, clients, uids, mut timer): Self::SystemData,
|
||||
_job: &mut Job<Self>,
|
||||
(entities, mut invites, mut pending_invites, clients, uids): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "invite_timeout::Sys::run");
|
||||
timer.start();
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
|
||||
let timed_out_invites = (&entities, &invites)
|
||||
.join()
|
||||
.filter_map(|(invitee, Invite { inviter, kind })| {
|
||||
@ -68,7 +67,5 @@ impl<'a> System<'a> for Sys {
|
||||
for entity in timed_out_invites {
|
||||
invites.remove(entity);
|
||||
}
|
||||
|
||||
timer.end();
|
||||
}
|
||||
}
|
||||
|
128
server/src/sys/metrics.rs
Normal file
128
server/src/sys/metrics.rs
Normal file
@ -0,0 +1,128 @@
|
||||
use crate::{
|
||||
metrics::{EcsSystemMetrics, PhysicsMetrics, TickMetrics},
|
||||
Tick, TickStart,
|
||||
};
|
||||
use common::{
|
||||
metrics::SysMetrics,
|
||||
resources::TimeOfDay,
|
||||
system::{Job, Origin, Phase, System},
|
||||
terrain::TerrainGrid,
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadExpect};
|
||||
use std::time::Instant;
|
||||
|
||||
/// This system exports metrics
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Option<Entities<'a>>,
|
||||
ReadExpect<'a, Tick>,
|
||||
ReadExpect<'a, TimeOfDay>,
|
||||
ReadExpect<'a, TickStart>,
|
||||
Option<Read<'a, TerrainGrid>>,
|
||||
Read<'a, SysMetrics>,
|
||||
Read<'a, common::metrics::PhysicsMetrics>,
|
||||
ReadExpect<'a, EcsSystemMetrics>,
|
||||
ReadExpect<'a, TickMetrics>,
|
||||
ReadExpect<'a, PhysicsMetrics>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "metrics";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Apply;
|
||||
|
||||
fn run(
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
tick,
|
||||
time_of_day,
|
||||
tick_start,
|
||||
terrain,
|
||||
sys_metrics,
|
||||
phys_metrics,
|
||||
export_ecs,
|
||||
export_tick,
|
||||
export_physics,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
const NANOSEC_PER_SEC: f64 = std::time::Duration::from_secs(1).as_nanos() as f64;
|
||||
|
||||
let start = Instant::now();
|
||||
|
||||
let mut state = sys_metrics.stats.lock().unwrap();
|
||||
//this system hasn't run yet
|
||||
state.remove(Self::NAME);
|
||||
|
||||
for (name, stat) in common::system::gen_stats(&state, tick_start.0, 8, 8) {
|
||||
export_ecs
|
||||
.system_start_time
|
||||
.with_label_values(&[&name])
|
||||
.set(stat.start_ns() as i64);
|
||||
export_ecs
|
||||
.system_thread_avg
|
||||
.with_label_values(&[&name])
|
||||
.set(stat.avg_threads() as f64);
|
||||
let len = stat.length_ns() as i64;
|
||||
export_ecs
|
||||
.system_length_time
|
||||
.with_label_values(&[&name])
|
||||
.set(len);
|
||||
export_ecs
|
||||
.system_length_hist
|
||||
.with_label_values(&[&name])
|
||||
.observe(len as f64 / NANOSEC_PER_SEC);
|
||||
}
|
||||
|
||||
// Report other info
|
||||
export_tick.time_of_day.set(time_of_day.0);
|
||||
if tick.0.rem_euclid(100) == 0 {
|
||||
if let Some(terrain) = terrain {
|
||||
let mut chonk_cnt = 0;
|
||||
let mut group_cnt = 0;
|
||||
let chunk_cnt = terrain.iter().fold(0, |a, (_, c)| {
|
||||
chonk_cnt += 1;
|
||||
group_cnt += c.sub_chunk_groups();
|
||||
a + c.sub_chunks_len()
|
||||
});
|
||||
export_tick.chonks_count.set(chonk_cnt as i64);
|
||||
export_tick.chunks_count.set(chunk_cnt as i64);
|
||||
export_tick.chunk_groups_count.set(group_cnt as i64);
|
||||
}
|
||||
|
||||
if let Some(entities) = entities {
|
||||
let entity_count = entities.join().count();
|
||||
export_tick.entity_count.set(entity_count as i64);
|
||||
}
|
||||
}
|
||||
|
||||
//detailed physics metrics
|
||||
export_physics
|
||||
.entity_entity_collision_checks_count
|
||||
.inc_by(phys_metrics.entity_entity_collision_checks);
|
||||
export_physics
|
||||
.entity_entity_collisions_count
|
||||
.inc_by(phys_metrics.entity_entity_collisions);
|
||||
|
||||
// export self time as best as possible
|
||||
export_ecs
|
||||
.system_start_time
|
||||
.with_label_values(&["metrics"])
|
||||
.set(start.duration_since(tick_start.0).as_nanos() as i64);
|
||||
export_ecs
|
||||
.system_thread_avg
|
||||
.with_label_values(&["metrics"])
|
||||
.set(1.0);
|
||||
let len = start.elapsed().as_nanos() as i64;
|
||||
export_ecs
|
||||
.system_length_time
|
||||
.with_label_values(&["metrics"])
|
||||
.set(len);
|
||||
export_ecs
|
||||
.system_length_hist
|
||||
.with_label_values(&["metrics"])
|
||||
.observe(len as f64 / NANOSEC_PER_SEC);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
pub mod agent;
|
||||
pub mod entity_sync;
|
||||
pub mod invite_timeout;
|
||||
pub mod metrics;
|
||||
pub mod msg;
|
||||
pub mod object;
|
||||
pub mod persistence;
|
||||
@ -10,59 +11,32 @@ pub mod terrain;
|
||||
pub mod terrain_sync;
|
||||
pub mod waypoint;
|
||||
|
||||
use common::system::{dispatch, run_now};
|
||||
use specs::DispatcherBuilder;
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
pub type EntitySyncTimer = SysTimer<entity_sync::Sys>;
|
||||
pub type GeneralMsgTimer = SysTimer<msg::general::Sys>;
|
||||
pub type PingMsgTimer = SysTimer<msg::ping::Sys>;
|
||||
pub type CharacterScreenMsgTimer = SysTimer<msg::character_screen::Sys>;
|
||||
pub type InGameMsgTimer = SysTimer<msg::in_game::Sys>;
|
||||
pub type SentinelTimer = SysTimer<sentinel::Sys>;
|
||||
pub type SubscriptionTimer = SysTimer<subscription::Sys>;
|
||||
pub type TerrainTimer = SysTimer<terrain::Sys>;
|
||||
pub type TerrainSyncTimer = SysTimer<terrain_sync::Sys>;
|
||||
pub type WaypointTimer = SysTimer<waypoint::Sys>;
|
||||
pub type InviteTimeoutTimer = SysTimer<invite_timeout::Sys>;
|
||||
pub type PersistenceTimer = SysTimer<persistence::Sys>;
|
||||
pub type PersistenceScheduler = SysScheduler<persistence::Sys>;
|
||||
pub type AgentTimer = SysTimer<agent::Sys>;
|
||||
|
||||
// System names
|
||||
// Note: commented names may be useful in the future
|
||||
//const ENTITY_SYNC_SYS: &str = "server_entity_sync_sys";
|
||||
//const SENTINEL_SYS: &str = "sentinel_sys";
|
||||
//const SUBSCRIPTION_SYS: &str = "server_subscription_sys";
|
||||
//const TERRAIN_SYNC_SYS: &str = "server_terrain_sync_sys";
|
||||
const TERRAIN_SYS: &str = "server_terrain_sys";
|
||||
const WAYPOINT_SYS: &str = "server_waypoint_sys";
|
||||
const INVITE_TIMEOUT_SYS: &str = "server_invite_timeout_sys";
|
||||
const PERSISTENCE_SYS: &str = "server_persistence_sys";
|
||||
const OBJECT_SYS: &str = "server_object_sys";
|
||||
pub const AGENT_SYS: &str = "agent_sys";
|
||||
|
||||
pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch_builder.add(terrain::Sys, TERRAIN_SYS, &[]);
|
||||
dispatch_builder.add(waypoint::Sys, WAYPOINT_SYS, &[]);
|
||||
dispatch_builder.add(invite_timeout::Sys, INVITE_TIMEOUT_SYS, &[]);
|
||||
dispatch_builder.add(persistence::Sys, PERSISTENCE_SYS, &[]);
|
||||
dispatch_builder.add(object::Sys, OBJECT_SYS, &[]);
|
||||
dispatch::<terrain::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<waypoint::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<invite_timeout::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<persistence::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<object::Sys>(dispatch_builder, &[]);
|
||||
}
|
||||
|
||||
pub fn run_sync_systems(ecs: &mut specs::World) {
|
||||
use specs::RunNow;
|
||||
|
||||
// Setup for entity sync
|
||||
// If I'm not mistaken, these two could be ran in parallel
|
||||
sentinel::Sys.run_now(ecs);
|
||||
subscription::Sys.run_now(ecs);
|
||||
run_now::<sentinel::Sys>(ecs);
|
||||
run_now::<subscription::Sys>(ecs);
|
||||
|
||||
// Sync
|
||||
terrain_sync::Sys.run_now(ecs);
|
||||
entity_sync::Sys.run_now(ecs);
|
||||
run_now::<terrain_sync::Sys>(ecs);
|
||||
run_now::<entity_sync::Sys>(ecs);
|
||||
}
|
||||
|
||||
/// Used to schedule systems to run at an interval
|
||||
@ -101,38 +75,3 @@ impl<S> Default for SysScheduler<S> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to keep track of how much time each system takes
|
||||
pub struct SysTimer<S> {
|
||||
pub nanos: u64,
|
||||
start: Option<Instant>,
|
||||
_phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<S> SysTimer<S> {
|
||||
pub fn start(&mut self) {
|
||||
if self.start.is_some() {
|
||||
panic!("Timer already started");
|
||||
}
|
||||
self.start = Some(Instant::now());
|
||||
}
|
||||
|
||||
pub fn end(&mut self) {
|
||||
self.nanos = self
|
||||
.start
|
||||
.take()
|
||||
.expect("Timer ended without starting it")
|
||||
.elapsed()
|
||||
.as_nanos() as u64;
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Default for SysTimer<S> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
nanos: 0,
|
||||
start: None,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
use super::super::SysTimer;
|
||||
use crate::{
|
||||
alias_validator::AliasValidator, character_creator, client::Client,
|
||||
persistence::character_loader::CharacterLoader, presence::Presence, EditableSettings,
|
||||
@ -6,11 +5,11 @@ use crate::{
|
||||
use common::{
|
||||
comp::{ChatType, Player, UnresolvedChatMsg},
|
||||
event::{EventBus, ServerEvent},
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::Uid,
|
||||
};
|
||||
use common_net::msg::{ClientGeneral, ServerGeneral};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage};
|
||||
use std::sync::atomic::Ordering;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
@ -121,6 +120,7 @@ impl Sys {
|
||||
}
|
||||
|
||||
/// This system will handle new messages from clients
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
@ -128,7 +128,6 @@ impl<'a> System<'a> for Sys {
|
||||
Entities<'a>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
ReadExpect<'a, CharacterLoader>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Client>,
|
||||
ReadStorage<'a, Player>,
|
||||
@ -137,13 +136,16 @@ impl<'a> System<'a> for Sys {
|
||||
ReadExpect<'a, AliasValidator>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "msg::character_screen";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
server_event_bus,
|
||||
character_loader,
|
||||
mut timer,
|
||||
uids,
|
||||
clients,
|
||||
players,
|
||||
@ -152,9 +154,6 @@ impl<'a> System<'a> for Sys {
|
||||
alias_validator,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "msg::character_screen::Sys::run");
|
||||
timer.start();
|
||||
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
let mut new_chat_msgs = Vec::new();
|
||||
|
||||
@ -189,7 +188,5 @@ impl<'a> System<'a> for Sys {
|
||||
server_emitter.emit(ServerEvent::Chat(msg));
|
||||
}
|
||||
}
|
||||
|
||||
timer.end()
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
use super::super::SysTimer;
|
||||
use crate::{client::Client, metrics::PlayerMetrics};
|
||||
use common::{
|
||||
comp::{ChatMode, Player, UnresolvedChatMsg},
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::Time,
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::Uid,
|
||||
};
|
||||
use common_net::msg::{
|
||||
validate_chat_msg, ChatMsgValidationError, ClientGeneral, MAX_BYTES_CHAT_MSG,
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage};
|
||||
use std::sync::atomic::Ordering;
|
||||
use tracing::{debug, error, warn};
|
||||
|
||||
@ -65,6 +64,7 @@ impl Sys {
|
||||
}
|
||||
|
||||
/// This system will handle new messages from clients
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
@ -73,30 +73,29 @@ impl<'a> System<'a> for Sys {
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
Read<'a, Time>,
|
||||
ReadExpect<'a, PlayerMetrics>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, ChatMode>,
|
||||
ReadStorage<'a, Player>,
|
||||
ReadStorage<'a, Client>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "msg::general";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
server_event_bus,
|
||||
time,
|
||||
player_metrics,
|
||||
mut timer,
|
||||
uids,
|
||||
chat_modes,
|
||||
players,
|
||||
clients,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "msg::general::Sys::run");
|
||||
timer.start();
|
||||
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
let mut new_chat_msgs = Vec::new();
|
||||
|
||||
@ -134,7 +133,5 @@ impl<'a> System<'a> for Sys {
|
||||
server_emitter.emit(ServerEvent::Chat(msg));
|
||||
}
|
||||
}
|
||||
|
||||
timer.end()
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,14 @@
|
||||
use super::super::SysTimer;
|
||||
use crate::{client::Client, metrics::NetworkRequestMetrics, presence::Presence, Settings};
|
||||
use common::{
|
||||
comp::{CanBuild, ControlEvent, Controller, ForceUpdate, Health, Ori, Pos, Stats, Vel},
|
||||
event::{EventBus, ServerEvent},
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
terrain::{TerrainChunkSize, TerrainGrid},
|
||||
vol::{ReadVol, RectVolSize},
|
||||
};
|
||||
use common_net::msg::{ClientGeneral, PresenceKind, ServerGeneral};
|
||||
use common_sys::state::BlockChange;
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write, WriteStorage};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, Write, WriteStorage};
|
||||
use tracing::{debug, trace};
|
||||
|
||||
impl Sys {
|
||||
@ -165,6 +164,7 @@ impl Sys {
|
||||
}
|
||||
|
||||
/// This system will handle new messages from clients
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
@ -173,7 +173,6 @@ impl<'a> System<'a> for Sys {
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
ReadExpect<'a, NetworkRequestMetrics>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, CanBuild>,
|
||||
ReadStorage<'a, ForceUpdate>,
|
||||
WriteStorage<'a, Stats>,
|
||||
@ -188,14 +187,17 @@ impl<'a> System<'a> for Sys {
|
||||
Read<'a, Settings>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "msg::in_game";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
server_event_bus,
|
||||
terrain,
|
||||
network_metrics,
|
||||
mut timer,
|
||||
can_build,
|
||||
force_updates,
|
||||
mut stats,
|
||||
@ -210,9 +212,6 @@ impl<'a> System<'a> for Sys {
|
||||
settings,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "msg::in_game::Sys::run");
|
||||
timer.start();
|
||||
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
|
||||
for (entity, client, mut maybe_presence) in
|
||||
@ -240,7 +239,5 @@ impl<'a> System<'a> for Sys {
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
timer.end()
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,11 @@
|
||||
use super::super::SysTimer;
|
||||
use crate::{client::Client, metrics::PlayerMetrics, Settings};
|
||||
use common::{
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::Time,
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
};
|
||||
use common_net::msg::PingMsg;
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, Write};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage};
|
||||
use std::sync::atomic::Ordering;
|
||||
use tracing::{debug, info};
|
||||
|
||||
@ -21,6 +20,7 @@ impl Sys {
|
||||
}
|
||||
|
||||
/// This system will handle new messages from clients
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
@ -29,26 +29,18 @@ impl<'a> System<'a> for Sys {
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
Read<'a, Time>,
|
||||
ReadExpect<'a, PlayerMetrics>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, Client>,
|
||||
Read<'a, Settings>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(
|
||||
entities,
|
||||
server_event_bus,
|
||||
time,
|
||||
player_metrics,
|
||||
mut timer,
|
||||
clients,
|
||||
settings,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "msg::ping::Sys::run");
|
||||
timer.start();
|
||||
const NAME: &'static str = "msg::ping";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
_job: &mut Job<Self>,
|
||||
(entities, server_event_bus, time, player_metrics, clients, settings): Self::SystemData,
|
||||
) {
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
|
||||
for (entity, client) in (&entities, &clients).join() {
|
||||
@ -89,7 +81,5 @@ impl<'a> System<'a> for Sys {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
timer.end()
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@ use common::{
|
||||
effect::Effect,
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::DeltaTime,
|
||||
span, Damage, DamageSource, Explosion, RadiusEffect,
|
||||
system::{Job, Origin, Phase, System},
|
||||
Damage, DamageSource, Explosion, RadiusEffect,
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
|
||||
|
||||
/// This system is responsible for handling misc object behaviours
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)]
|
||||
@ -21,11 +23,14 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Object>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "object";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(entities, _dt, server_bus, positions, velocities, physics_states, mut objects): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "object::Sys::run");
|
||||
let mut server_emitter = server_bus.emitter();
|
||||
|
||||
// Objects
|
||||
|
@ -1,19 +1,16 @@
|
||||
use crate::{
|
||||
persistence::character_updater,
|
||||
presence::Presence,
|
||||
sys::{SysScheduler, SysTimer},
|
||||
};
|
||||
use crate::{persistence::character_updater, presence::Presence, sys::SysScheduler};
|
||||
use common::{
|
||||
comp::{Inventory, Stats, Waypoint},
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
};
|
||||
use common_net::msg::PresenceKind;
|
||||
use specs::{Join, ReadExpect, ReadStorage, System, Write};
|
||||
use specs::{Join, ReadExpect, ReadStorage, Write};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
ReadStorage<'a, Presence>,
|
||||
ReadStorage<'a, Stats>,
|
||||
@ -21,11 +18,14 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Waypoint>,
|
||||
ReadExpect<'a, character_updater::CharacterUpdater>,
|
||||
Write<'a, SysScheduler<Self>>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "persistence";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
presences,
|
||||
player_stats,
|
||||
@ -33,12 +33,9 @@ impl<'a> System<'a> for Sys {
|
||||
player_waypoint,
|
||||
updater,
|
||||
mut scheduler,
|
||||
mut timer,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "persistence::Sys::run");
|
||||
if scheduler.should_run() {
|
||||
timer.start();
|
||||
updater.batch_update(
|
||||
(
|
||||
&presences,
|
||||
@ -54,7 +51,6 @@ impl<'a> System<'a> for Sys {
|
||||
},
|
||||
),
|
||||
);
|
||||
timer.end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
use super::SysTimer;
|
||||
use common::{
|
||||
comp::{
|
||||
Auras, BeamSegment, Body, Buffs, CanBuild, CharacterState, Collider, Combo, Energy,
|
||||
Gravity, Group, Health, Inventory, Item, LightEmitter, Mass, MountState, Mounting, Ori,
|
||||
Player, Poise, Pos, Scale, Shockwave, Stats, Sticky, Vel,
|
||||
},
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::Uid,
|
||||
};
|
||||
use common_net::{
|
||||
@ -14,29 +13,25 @@ use common_net::{
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use specs::{
|
||||
shred::ResourceId, Entity as EcsEntity, Join, ReadExpect, ReadStorage, System, SystemData,
|
||||
World, Write, WriteExpect,
|
||||
shred::ResourceId, Entity as EcsEntity, Join, ReadExpect, ReadStorage, SystemData, World,
|
||||
WriteExpect,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
/// Always watching
|
||||
/// This system will monitor specific components for insertion, removal, and
|
||||
/// modification
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = (
|
||||
Write<'a, SysTimer<Self>>,
|
||||
TrackedComps<'a>,
|
||||
WriteTrackers<'a>,
|
||||
);
|
||||
type SystemData = (TrackedComps<'a>, WriteTrackers<'a>);
|
||||
|
||||
fn run(&mut self, (mut timer, comps, mut trackers): Self::SystemData) {
|
||||
span!(_guard, "run", "sentinel::Sys::run");
|
||||
timer.start();
|
||||
const NAME: &'static str = "sentinel";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(_job: &mut Job<Self>, (comps, mut trackers): Self::SystemData) {
|
||||
record_changes(&comps, &mut trackers);
|
||||
|
||||
timer.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
use super::{
|
||||
sentinel::{DeletedEntities, TrackedComps},
|
||||
SysTimer,
|
||||
};
|
||||
use super::sentinel::{DeletedEntities, TrackedComps};
|
||||
use crate::{
|
||||
client::Client,
|
||||
presence::{self, Presence, RegionSubscription},
|
||||
@ -9,27 +6,26 @@ use crate::{
|
||||
use common::{
|
||||
comp::{Ori, Pos, Vel},
|
||||
region::{region_in_vd, regions_in_vd, Event as RegionEvent, RegionMap},
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
terrain::TerrainChunkSize,
|
||||
uid::Uid,
|
||||
vol::RectVolSize,
|
||||
};
|
||||
use common_net::msg::ServerGeneral;
|
||||
use specs::{
|
||||
Entities, Join, ReadExpect, ReadStorage, System, SystemData, World, WorldExt, Write,
|
||||
WriteStorage,
|
||||
Entities, Join, ReadExpect, ReadStorage, SystemData, World, WorldExt, Write, WriteStorage,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
use vek::*;
|
||||
|
||||
/// This system will update region subscriptions based on client positions
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadExpect<'a, RegionMap>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Vel>,
|
||||
@ -41,13 +37,16 @@ impl<'a> System<'a> for Sys {
|
||||
TrackedComps<'a>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "subscription";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
#[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
region_map,
|
||||
mut timer,
|
||||
uids,
|
||||
positions,
|
||||
velocities,
|
||||
@ -59,9 +58,6 @@ impl<'a> System<'a> for Sys {
|
||||
tracked_comps,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "subscription::Sys::run");
|
||||
timer.start();
|
||||
|
||||
// To update subscriptions
|
||||
// 1. Iterate through clients
|
||||
// 2. Calculate current chunk position
|
||||
@ -209,8 +205,6 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer.end();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
use super::SysTimer;
|
||||
use crate::{
|
||||
chunk_generator::ChunkGenerator, client::Client, presence::Presence, rtsim::RtSim, Tick,
|
||||
};
|
||||
@ -7,13 +6,13 @@ use common::{
|
||||
event::{EventBus, ServerEvent},
|
||||
generation::get_npc_name,
|
||||
npc::NPC_NAMES,
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
terrain::TerrainGrid,
|
||||
LoadoutBuilder, SkillSetBuilder,
|
||||
};
|
||||
use common_net::msg::ServerGeneral;
|
||||
use common_sys::state::TerrainChanges;
|
||||
use specs::{Join, Read, ReadStorage, System, Write, WriteExpect};
|
||||
use specs::{Join, Read, ReadStorage, Write, WriteExpect};
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
|
||||
@ -23,13 +22,13 @@ use vek::*;
|
||||
/// 2. Sends new chunks to nearby clients
|
||||
/// 3. Handles the chunk's supplement (e.g. npcs)
|
||||
/// 4. Removes chunks outside the range of players
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
type SystemData = (
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
Read<'a, Tick>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
WriteExpect<'a, ChunkGenerator>,
|
||||
WriteExpect<'a, TerrainGrid>,
|
||||
Write<'a, TerrainChanges>,
|
||||
@ -39,12 +38,15 @@ impl<'a> System<'a> for Sys {
|
||||
ReadStorage<'a, Client>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "terrain";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
server_event_bus,
|
||||
tick,
|
||||
mut timer,
|
||||
mut chunk_generator,
|
||||
mut terrain,
|
||||
mut terrain_changes,
|
||||
@ -54,9 +56,6 @@ impl<'a> System<'a> for Sys {
|
||||
clients,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "terrain::Sys::run");
|
||||
timer.start();
|
||||
|
||||
let mut server_emitter = server_event_bus.emitter();
|
||||
|
||||
// Fetch any generated `TerrainChunk`s and insert them into the terrain.
|
||||
@ -236,8 +235,6 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
chunk_generator.cancel_if_pending(key);
|
||||
}
|
||||
|
||||
timer.end()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,31 +1,35 @@
|
||||
use super::SysTimer;
|
||||
use crate::{client::Client, presence::Presence};
|
||||
use common::{comp::Pos, span, terrain::TerrainGrid};
|
||||
use common::{
|
||||
comp::Pos,
|
||||
system::{Job, Origin, Phase, System},
|
||||
terrain::TerrainGrid,
|
||||
};
|
||||
use common_net::msg::ServerGeneral;
|
||||
use common_sys::state::TerrainChanges;
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, System, Write};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage};
|
||||
|
||||
/// This systems sends new chunks to clients as well as changes to existing
|
||||
/// chunks
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Read<'a, TerrainChanges>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, Pos>,
|
||||
ReadStorage<'a, Presence>,
|
||||
ReadStorage<'a, Client>,
|
||||
);
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
(terrain, terrain_changes, mut timer, positions, presences, clients): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "terrain_sync::Sys::run");
|
||||
timer.start();
|
||||
const NAME: &'static str = "terrain_sync";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
_job: &mut Job<Self>,
|
||||
(terrain, terrain_changes, positions, presences, clients): Self::SystemData,
|
||||
) {
|
||||
// Sync changed chunks
|
||||
'chunk: for chunk_key in &terrain_changes.modified_chunks {
|
||||
let mut lazy_msg = None;
|
||||
@ -58,7 +62,5 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
lazy_msg.as_ref().map(|ref msg| client.send_prepared(&msg));
|
||||
}
|
||||
|
||||
timer.end();
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,21 @@
|
||||
use super::SysTimer;
|
||||
use crate::client::Client;
|
||||
use common::{
|
||||
comp::{Player, Pos, Waypoint, WaypointArea},
|
||||
resources::Time,
|
||||
span,
|
||||
system::{Job, Origin, Phase, System},
|
||||
};
|
||||
use common_net::msg::{Notification, ServerGeneral};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, Write, WriteStorage};
|
||||
use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
|
||||
|
||||
/// Cooldown time (in seconds) for "Waypoint Saved" notifications
|
||||
const NOTIFY_TIME: f64 = 10.0;
|
||||
|
||||
/// This system updates player waypoints
|
||||
/// TODO: Make this faster by only considering local waypoints
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadStorage<'a, Pos>,
|
||||
@ -24,11 +24,14 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Waypoint>,
|
||||
ReadStorage<'a, Client>,
|
||||
Read<'a, Time>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "waypoint";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(
|
||||
entities,
|
||||
positions,
|
||||
@ -37,12 +40,8 @@ impl<'a> System<'a> for Sys {
|
||||
mut waypoints,
|
||||
clients,
|
||||
time,
|
||||
mut timer,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "run", "waypoint::Sys::run");
|
||||
timer.start();
|
||||
|
||||
for (entity, player_pos, _, client) in (&entities, &positions, &players, &clients).join() {
|
||||
for (waypoint_pos, waypoint_area) in (&positions, &waypoint_areas).join() {
|
||||
if player_pos.0.distance_squared(waypoint_pos.0) < waypoint_area.radius().powi(2) {
|
||||
@ -57,7 +56,5 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer.end();
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,10 @@
|
||||
pub mod floater;
|
||||
mod interpolation;
|
||||
|
||||
use common::system::{dispatch, System};
|
||||
use specs::DispatcherBuilder;
|
||||
|
||||
// System names
|
||||
const FLOATER_SYS: &str = "floater_voxygen_sys";
|
||||
const INTERPOLATION_SYS: &str = "interpolation_voxygen_sys";
|
||||
|
||||
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch_builder.add(interpolation::Sys, INTERPOLATION_SYS, &[
|
||||
common_sys::PHYS_SYS,
|
||||
]);
|
||||
dispatch_builder.add(floater::Sys, FLOATER_SYS, &[INTERPOLATION_SYS]);
|
||||
dispatch::<interpolation::Sys>(dispatch_builder, &[&common_sys::phys::Sys::sys_name()]);
|
||||
dispatch::<floater::Sys>(dispatch_builder, &[&interpolation::Sys::sys_name()]);
|
||||
}
|
||||
|
@ -5,18 +5,20 @@ use crate::ecs::{
|
||||
use common::{
|
||||
comp::{Health, HealthSource, Pos},
|
||||
resources::DeltaTime,
|
||||
system::{Job, Origin, Phase, System},
|
||||
uid::Uid,
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use specs::{Entities, Join, Read, ReadExpect, ReadStorage, WriteStorage};
|
||||
|
||||
// How long floaters last (in seconds)
|
||||
pub const HP_SHOWTIME: f32 = 3.0;
|
||||
pub const MY_HP_SHOWTIME: f32 = 2.5;
|
||||
pub const HP_ACCUMULATETIME: f32 = 1.0;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
ReadExpect<'a, MyEntity>,
|
||||
@ -27,9 +29,13 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, HpFloaterList>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "floater";
|
||||
const ORIGIN: Origin = Origin::Frontend("voxygen");
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
#[allow(clippy::blocks_in_if_conditions)] // TODO: Pending review in #587
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(entities, my_entity, dt, uids, pos, healths, mut hp_floater_lists): Self::SystemData,
|
||||
) {
|
||||
// Add hp floater lists to all entities with health and a position
|
||||
|
@ -2,15 +2,17 @@ use crate::ecs::comp::Interpolated;
|
||||
use common::{
|
||||
comp::{object, Body, Ori, Pos, Vel},
|
||||
resources::DeltaTime,
|
||||
system::{Job, Origin, Phase, System},
|
||||
};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
use specs::{Entities, Join, Read, ReadStorage, WriteStorage};
|
||||
use tracing::warn;
|
||||
use vek::*;
|
||||
|
||||
/// This system will allow NPCs to modify their controller
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
#[allow(clippy::type_complexity)] // TODO: Pending review in #587
|
||||
#[allow(clippy::type_complexity)]
|
||||
type SystemData = (
|
||||
Entities<'a>,
|
||||
Read<'a, DeltaTime>,
|
||||
@ -21,8 +23,12 @@ impl<'a> System<'a> for Sys {
|
||||
WriteStorage<'a, Interpolated>,
|
||||
);
|
||||
|
||||
const NAME: &'static str = "interpolation";
|
||||
const ORIGIN: Origin = Origin::Frontend("voxygen");
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
_job: &mut Job<Self>,
|
||||
(entities, dt, positions, orientations, velocities, bodies, mut interpolated): Self::SystemData,
|
||||
) {
|
||||
// Update interpolated positions and orientations
|
||||
|
Loading…
Reference in New Issue
Block a user