mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
add metrics for physics sys and implement concurrent physics
This commit is contained in:
parent
bbe6e8be7c
commit
ce3173ecdf
@ -6,8 +6,8 @@ rustflags = [
|
||||
[alias]
|
||||
generate = "run --package tools --"
|
||||
test-server = "-Zpackage-features run --bin veloren-server-cli --no-default-features"
|
||||
tracy-server = "-Zunstable-options -Zpackage-features run --bin veloren-server-cli --no-default-features --features tracy --profile no_overflow"
|
||||
tracy-server = "-Zunstable-options -Zpackage-features run --bin veloren-server-cli --no-default-features --features tracy --profile releasedebuginfo"
|
||||
test-voxygen = "-Zpackage-features run --bin veloren-voxygen --no-default-features --features gl"
|
||||
tracy-voxygen = "-Zunstable-options -Zpackage-features run --bin veloren-voxygen --no-default-features --features tracy,gl --profile no_overflow"
|
||||
tracy-voxygen = "-Zunstable-options -Zpackage-features run --bin veloren-voxygen --no-default-features --features tracy,gl --profile releasedebuginfo"
|
||||
server = "run --bin veloren-server-cli"
|
||||
|
||||
|
@ -11,3 +11,10 @@ pub struct SysMetrics {
|
||||
pub projectile_ns: AtomicI64,
|
||||
pub melee_ns: AtomicI64,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PhysicsMetrics {
|
||||
pub velocities_cache_len: i64,
|
||||
pub entity_entity_collision_checks: i64,
|
||||
pub entity_entity_collisions: i64,
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
comp,
|
||||
event::{EventBus, LocalEvent, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
metrics::{PhysicsMetrics, SysMetrics},
|
||||
region::RegionMap,
|
||||
sync::WorldSyncExt,
|
||||
sys,
|
||||
@ -183,6 +183,7 @@ impl State {
|
||||
ecs.insert(comp::group::GroupManager::default());
|
||||
ecs.insert(RegionMap::new());
|
||||
ecs.insert(SysMetrics::default());
|
||||
ecs.insert(PhysicsMetrics::default());
|
||||
|
||||
ecs
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
Shockwave, Sticky, Vel,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
metrics::SysMetrics,
|
||||
metrics::{PhysicsMetrics, SysMetrics},
|
||||
span,
|
||||
state::DeltaTime,
|
||||
sync::Uid,
|
||||
@ -12,7 +12,9 @@ use crate::{
|
||||
vol::ReadVol,
|
||||
};
|
||||
use rayon::iter::ParallelIterator;
|
||||
use specs::{Entities, Join, ParJoin, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use specs::{
|
||||
Entities, Join, ParJoin, Read, ReadExpect, ReadStorage, System, WriteExpect, WriteStorage,
|
||||
};
|
||||
use std::ops::Range;
|
||||
use vek::*;
|
||||
|
||||
@ -53,6 +55,7 @@ impl<'a> System<'a> for Sys {
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Read<'a, DeltaTime>,
|
||||
ReadExpect<'a, SysMetrics>,
|
||||
WriteExpect<'a, PhysicsMetrics>,
|
||||
Read<'a, EventBus<ServerEvent>>,
|
||||
ReadStorage<'a, Scale>,
|
||||
ReadStorage<'a, Sticky>,
|
||||
@ -79,6 +82,7 @@ impl<'a> System<'a> for Sys {
|
||||
terrain,
|
||||
dt,
|
||||
sys_metrics,
|
||||
mut physics_metrics,
|
||||
event_bus,
|
||||
scales,
|
||||
stickies,
|
||||
@ -143,7 +147,7 @@ impl<'a> System<'a> for Sys {
|
||||
.join()
|
||||
{
|
||||
let id = entity.id() as usize;
|
||||
let vel_dt = vel.0.clone() * dt.0;
|
||||
let vel_dt = vel.0 * dt.0;
|
||||
if id >= old_velocities_times_dt.len() {
|
||||
old_velocities_times_dt.resize(id + 1, Vec3::zero());
|
||||
}
|
||||
@ -151,7 +155,7 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
drop(guard);
|
||||
span!(guard, "Apply pushback");
|
||||
for (entity, pos, vel, scale, mass, collider, _, _, physics, projectile) in (
|
||||
let metrics = (
|
||||
&entities,
|
||||
&positions,
|
||||
&mut velocities,
|
||||
@ -165,120 +169,138 @@ impl<'a> System<'a> for Sys {
|
||||
// should interact into the collider component or into a separate component
|
||||
projectiles.maybe(),
|
||||
)
|
||||
.join()
|
||||
.par_join()
|
||||
.filter(|(_, _, _, _, _, _, _, sticky, physics, _)| {
|
||||
sticky.is_none() || (physics.on_wall.is_none() && !physics.on_ground)
|
||||
})
|
||||
{
|
||||
let scale = scale.map(|s| s.0).unwrap_or(1.0);
|
||||
let radius = collider.map(|c| c.get_radius()).unwrap_or(0.5);
|
||||
let z_limits = collider.map(|c| c.get_z_limits()).unwrap_or((-0.5, 0.5));
|
||||
let mass = mass.map(|m| m.0).unwrap_or(scale);
|
||||
let vel_dt = old_velocities_times_dt[entity.id() as usize];
|
||||
.fold(PhysicsMetrics::default,
|
||||
|mut metrics,(entity, pos, vel, scale, mass, collider, _, _, physics, projectile)| {
|
||||
let scale = scale.map(|s| s.0).unwrap_or(1.0);
|
||||
let radius = collider.map(|c| c.get_radius()).unwrap_or(0.5);
|
||||
let z_limits = collider.map(|c| c.get_z_limits()).unwrap_or((-0.5, 0.5));
|
||||
let mass = mass.map(|m| m.0).unwrap_or(scale);
|
||||
let vel_dt = old_velocities_times_dt[entity.id() as usize];
|
||||
|
||||
// Resets touch_entities in physics
|
||||
physics.touch_entities.clear();
|
||||
// Resets touch_entities in physics
|
||||
physics.touch_entities.clear();
|
||||
|
||||
let is_projectile = projectile.is_some();
|
||||
let is_projectile = projectile.is_some();
|
||||
|
||||
let mut vel_delta = Vec3::zero();
|
||||
let mut vel_delta = Vec3::zero();
|
||||
|
||||
for (
|
||||
entity_other,
|
||||
other,
|
||||
pos_other,
|
||||
scale_other,
|
||||
mass_other,
|
||||
collider_other,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
) in (
|
||||
&entities,
|
||||
&uids,
|
||||
&positions,
|
||||
scales.maybe(),
|
||||
masses.maybe(),
|
||||
colliders.maybe(),
|
||||
!&projectiles,
|
||||
!&mountings,
|
||||
!&beams,
|
||||
!&shockwaves,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
if entity == entity_other {
|
||||
continue;
|
||||
}
|
||||
|
||||
let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0);
|
||||
let radius_other = collider_other.map(|c| c.get_radius()).unwrap_or(0.5);
|
||||
|
||||
let collision_dist = scale * radius + scale_other * radius_other;
|
||||
let collision_dist_sqr = collision_dist * collision_dist;
|
||||
let vel_dt_other = old_velocities_times_dt[entity_other.id() as usize];
|
||||
|
||||
let pos_diff_squared = (pos.0 - pos_other.0).magnitude_squared();
|
||||
let vel_diff_squared = (vel_dt - vel_dt_other).magnitude_squared();
|
||||
|
||||
// Sanity check: don't try colliding entities that are too far from each other
|
||||
// Note: I think this catches all cases. If you get entity collision problems,
|
||||
// try removing this!
|
||||
if pos_diff_squared > vel_diff_squared + collision_dist_sqr {
|
||||
continue;
|
||||
}
|
||||
|
||||
let z_limits_other = collider_other
|
||||
.map(|c| c.get_z_limits())
|
||||
.unwrap_or((-0.5, 0.5));
|
||||
let mass_other = mass_other.map(|m| m.0).unwrap_or(scale_other);
|
||||
//This check after the pos check, as we currently don't have that many massless
|
||||
// entites [citation needed]
|
||||
if mass_other == 0.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
const MIN_COLLISION_DIST: f32 = 0.3;
|
||||
let increments = (vel_diff_squared.sqrt() / MIN_COLLISION_DIST)
|
||||
.max(1.0)
|
||||
.ceil() as usize;
|
||||
let step_delta = 1.0 / increments as f32;
|
||||
let mut collided = false;
|
||||
|
||||
for i in 0..increments {
|
||||
let factor = i as f32 * step_delta;
|
||||
let pos = pos.0 + vel_dt * factor;
|
||||
let pos_other = pos_other.0 + vel_dt_other * factor;
|
||||
|
||||
let diff = pos.xy() - pos_other.xy();
|
||||
|
||||
if diff.magnitude_squared() <= collision_dist_sqr
|
||||
&& pos.z + z_limits.1 * scale
|
||||
>= pos_other.z + z_limits_other.0 * scale_other
|
||||
&& pos.z + z_limits.0 * scale
|
||||
<= pos_other.z + z_limits_other.1 * scale_other
|
||||
for (
|
||||
entity_other,
|
||||
other,
|
||||
pos_other,
|
||||
scale_other,
|
||||
mass_other,
|
||||
collider_other,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
_,
|
||||
) in (
|
||||
&entities,
|
||||
&uids,
|
||||
&positions,
|
||||
scales.maybe(),
|
||||
masses.maybe(),
|
||||
colliders.maybe(),
|
||||
!&projectiles,
|
||||
!&mountings,
|
||||
!&beams,
|
||||
!&shockwaves,
|
||||
)
|
||||
.join()
|
||||
{
|
||||
if !collided {
|
||||
physics.touch_entities.push(*other);
|
||||
if entity == entity_other {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't apply repulsive force to projectiles
|
||||
if diff.magnitude_squared() > 0.0 && !is_projectile {
|
||||
let force = 400.0 * (collision_dist - diff.magnitude()) * mass_other
|
||||
/ (mass + mass_other);
|
||||
let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0);
|
||||
let radius_other = collider_other.map(|c| c.get_radius()).unwrap_or(0.5);
|
||||
|
||||
vel_delta += Vec3::from(diff.normalized()) * force * step_delta;
|
||||
let collision_dist = scale * radius + scale_other * radius_other;
|
||||
let collision_dist_sqr = collision_dist * collision_dist;
|
||||
let vel_dt_other = old_velocities_times_dt[entity_other.id() as usize];
|
||||
|
||||
let pos_diff_squared = (pos.0 - pos_other.0).magnitude_squared();
|
||||
let vel_diff_squared = (vel_dt - vel_dt_other).magnitude_squared();
|
||||
|
||||
// Sanity check: don't try colliding entities that are too far from each
|
||||
// other Note: I think this catches all cases. If
|
||||
// you get entity collision problems, try removing
|
||||
// this!
|
||||
if pos_diff_squared > vel_diff_squared + collision_dist_sqr {
|
||||
continue;
|
||||
}
|
||||
|
||||
collided = true;
|
||||
let z_limits_other = collider_other
|
||||
.map(|c| c.get_z_limits())
|
||||
.unwrap_or((-0.5, 0.5));
|
||||
let mass_other = mass_other.map(|m| m.0).unwrap_or(scale_other);
|
||||
//This check after the pos check, as we currently don't have that many
|
||||
// massless entites [citation needed]
|
||||
if mass_other == 0.0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
metrics.entity_entity_collision_checks += 1;
|
||||
|
||||
const MIN_COLLISION_DIST: f32 = 0.3;
|
||||
let increments = (vel_diff_squared.sqrt() / MIN_COLLISION_DIST)
|
||||
.max(1.0)
|
||||
.ceil() as usize;
|
||||
let step_delta = 1.0 / increments as f32;
|
||||
let mut collided = false;
|
||||
|
||||
for i in 0..increments {
|
||||
let factor = i as f32 * step_delta;
|
||||
let pos = pos.0 + vel_dt * factor;
|
||||
let pos_other = pos_other.0 + vel_dt_other * factor;
|
||||
|
||||
let diff = pos.xy() - pos_other.xy();
|
||||
|
||||
if diff.magnitude_squared() <= collision_dist_sqr
|
||||
&& pos.z + z_limits.1 * scale
|
||||
>= pos_other.z + z_limits_other.0 * scale_other
|
||||
&& pos.z + z_limits.0 * scale
|
||||
<= pos_other.z + z_limits_other.1 * scale_other
|
||||
{
|
||||
if !collided {
|
||||
physics.touch_entities.push(*other);
|
||||
metrics.entity_entity_collisions += 1;
|
||||
}
|
||||
|
||||
// Don't apply repulsive force to projectiles
|
||||
if diff.magnitude_squared() > 0.0 && !is_projectile {
|
||||
let force =
|
||||
400.0 * (collision_dist - diff.magnitude()) * mass_other
|
||||
/ (mass + mass_other);
|
||||
|
||||
vel_delta += Vec3::from(diff.normalized()) * force * step_delta;
|
||||
}
|
||||
|
||||
collided = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change velocity
|
||||
vel.0 += vel_delta * dt.0;
|
||||
}
|
||||
// Change velocity
|
||||
vel.0 += vel_delta * dt.0;
|
||||
metrics
|
||||
},
|
||||
)
|
||||
.reduce(PhysicsMetrics::default, |old, new| {
|
||||
PhysicsMetrics {
|
||||
velocities_cache_len: 0,
|
||||
entity_entity_collision_checks: old.entity_entity_collision_checks + new.entity_entity_collision_checks,
|
||||
entity_entity_collisions: old.entity_entity_collisions + new.entity_entity_collisions,
|
||||
}
|
||||
});
|
||||
physics_metrics.velocities_cache_len = old_velocities_times_dt.len() as i64;
|
||||
physics_metrics.entity_entity_collision_checks = metrics.entity_entity_collision_checks;
|
||||
physics_metrics.entity_entity_collisions = metrics.entity_entity_collisions;
|
||||
drop(guard);
|
||||
|
||||
// Apply movement inputs
|
||||
|
@ -59,7 +59,7 @@ use common::{
|
||||
vol::{ReadVol, RectVolSize},
|
||||
};
|
||||
use futures_executor::block_on;
|
||||
use metrics::{ServerMetrics, StateTickMetrics, TickMetrics};
|
||||
use metrics::{PhysicsMetrics, ServerMetrics, StateTickMetrics, TickMetrics};
|
||||
use network::{Network, Pid, ProtocolAddr};
|
||||
use persistence::{
|
||||
character_loader::{CharacterLoader, CharacterLoaderResponseType},
|
||||
@ -108,6 +108,7 @@ pub struct Server {
|
||||
metrics: ServerMetrics,
|
||||
tick_metrics: TickMetrics,
|
||||
state_tick_metrics: StateTickMetrics,
|
||||
physics_metrics: PhysicsMetrics,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
@ -327,12 +328,14 @@ impl Server {
|
||||
let (tick_metrics, registry_tick) = TickMetrics::new(metrics.tick_clone())
|
||||
.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();
|
||||
|
||||
registry_chunk(&metrics.registry()).expect("failed to register chunk gen metrics");
|
||||
registry_network(&metrics.registry()).expect("failed to register network request metrics");
|
||||
registry_player(&metrics.registry()).expect("failed to register player metrics");
|
||||
registry_tick(&metrics.registry()).expect("failed to register tick metrics");
|
||||
registry_state(&metrics.registry()).expect("failed to register state metrics");
|
||||
registry_physics(&metrics.registry()).expect("failed to register state metrics");
|
||||
|
||||
let thread_pool = ThreadPoolBuilder::new()
|
||||
.name("veloren-worker".to_string())
|
||||
@ -358,6 +361,7 @@ impl Server {
|
||||
metrics,
|
||||
tick_metrics,
|
||||
state_tick_metrics,
|
||||
physics_metrics,
|
||||
};
|
||||
|
||||
debug!(?settings, "created veloren server with");
|
||||
@ -777,6 +781,24 @@ impl Server {
|
||||
.observe(melee_ns as f64 / NANOSEC_PER_SEC);
|
||||
}
|
||||
|
||||
//detailed physics metrics
|
||||
{
|
||||
let res = self
|
||||
.state
|
||||
.ecs()
|
||||
.read_resource::<common::metrics::PhysicsMetrics>();
|
||||
|
||||
self.physics_metrics
|
||||
.velocities_cache_len
|
||||
.set(res.velocities_cache_len);
|
||||
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
|
||||
|
@ -17,6 +17,12 @@ use tracing::{debug, error};
|
||||
|
||||
type RegistryFn = Box<dyn FnOnce(&Registry) -> Result<(), prometheus::Error>>;
|
||||
|
||||
pub struct PhysicsMetrics {
|
||||
pub velocities_cache_len: IntGauge,
|
||||
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
|
||||
// need the Historgram
|
||||
@ -62,6 +68,44 @@ pub struct ServerMetrics {
|
||||
tick: Arc<AtomicU64>,
|
||||
}
|
||||
|
||||
impl PhysicsMetrics {
|
||||
pub fn new() -> Result<(Self, RegistryFn), prometheus::Error> {
|
||||
let velocities_cache_len = IntGauge::with_opts(Opts::new(
|
||||
"velocities_cache_len",
|
||||
"shows the size of the velocities_cache in entries",
|
||||
))?;
|
||||
let entity_entity_collision_checks_count = IntCounter::with_opts(Opts::new(
|
||||
"entity_entity_collision_checks_count",
|
||||
"shows the number of collision checks",
|
||||
))?;
|
||||
let entity_entity_collisions_count = IntCounter::with_opts(Opts::new(
|
||||
"entity_entity_collisions_count",
|
||||
"shows the number of actual collisions detected",
|
||||
))?;
|
||||
|
||||
let velocities_cache_len_clone = velocities_cache_len.clone();
|
||||
let entity_entity_collision_checks_count_clone =
|
||||
entity_entity_collision_checks_count.clone();
|
||||
let entity_entity_collisions_count_clone = entity_entity_collisions_count.clone();
|
||||
|
||||
let f = |registry: &Registry| {
|
||||
registry.register(Box::new(velocities_cache_len_clone))?;
|
||||
registry.register(Box::new(entity_entity_collision_checks_count_clone))?;
|
||||
registry.register(Box::new(entity_entity_collisions_count_clone))?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
velocities_cache_len,
|
||||
entity_entity_collision_checks_count,
|
||||
entity_entity_collisions_count,
|
||||
},
|
||||
Box::new(f),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl StateTickMetrics {
|
||||
pub fn new() -> Result<(Self, RegistryFn), prometheus::Error> {
|
||||
let bucket = vec![
|
||||
|
Loading…
Reference in New Issue
Block a user