use core::time::Duration;
use bevy::{
diagnostic::{Diagnostic, DiagnosticPath, Diagnostics, DiagnosticsStore, RegisterDiagnostic},
prelude::*,
};
use crate::diagnostics::impl_diagnostic_paths;
use super::{AppDiagnosticsExt, PhysicsDiagnostics, PhysicsSchedule, PhysicsStepSystems};
pub struct PhysicsTotalDiagnosticsPlugin;
impl Plugin for PhysicsTotalDiagnosticsPlugin {
fn build(&self, app: &mut App) {
app.register_physics_diagnostics::<PhysicsTotalDiagnostics>();
#[cfg(feature = "bevy_diagnostic")]
app.register_diagnostic(
Diagnostic::new(PhysicsTotalDiagnostics::MISCELLANEOUS.clone()).with_suffix("ms"),
);
app.insert_resource::<PhysicsStepStart>(PhysicsStepStart(crate::utils::Instant::now()));
app.add_systems(
PhysicsSchedule,
(
(update_physics_step_start, increment_physics_step_number)
.in_set(PhysicsStepSystems::First),
update_step_time.in_set(PhysicsStepSystems::Last),
#[cfg(feature = "bevy_diagnostic")]
update_miscellaneous_physics_timer.after(PhysicsStepSystems::Last),
),
);
}
}
#[derive(Resource, Debug, Default, Reflect)]
#[reflect(Resource, Debug)]
pub struct PhysicsTotalDiagnostics {
pub step_number: u32,
pub step_time: Duration,
}
impl PhysicsDiagnostics for PhysicsTotalDiagnostics {
fn counter_paths(&self) -> Vec<(&'static DiagnosticPath, u32)> {
vec![(Self::STEP_NUMBER, self.step_number)]
}
fn timer_paths(&self) -> Vec<(&'static DiagnosticPath, Duration)> {
vec![(Self::STEP_TIME, self.step_time)]
}
}
impl_diagnostic_paths! {
impl PhysicsTotalDiagnostics {
STEP_NUMBER: "avian/step_number",
STEP_TIME: "avian/total_step_time",
MISCELLANEOUS: "avian/miscellaneous",
}
}
fn increment_physics_step_number(
mut diagnostics: ResMut<PhysicsTotalDiagnostics>,
mut step: Local<u32>,
) {
*step += 1;
diagnostics.step_number = *step;
}
#[derive(Resource, Debug, Reflect)]
#[reflect(Resource, Debug)]
struct PhysicsStepStart(pub crate::utils::Instant);
fn update_physics_step_start(mut start: ResMut<PhysicsStepStart>) {
start.0 = crate::utils::Instant::now();
}
fn update_step_time(
start: Res<PhysicsStepStart>,
mut diagnostics: ResMut<PhysicsTotalDiagnostics>,
) {
diagnostics.step_time = start.0.elapsed();
}
#[cfg(feature = "bevy_diagnostic")]
fn update_miscellaneous_physics_timer(mut diagnostics: Diagnostics, store: Res<DiagnosticsStore>) {
let total = store
.get(PhysicsTotalDiagnostics::STEP_TIME)
.and_then(|d| d.measurement().map(|m| m.value))
.unwrap_or(0.0);
let timed: f64 = store
.iter()
.filter_map(|d| {
if (d.suffix != "s" && d.suffix != "ms" && d.suffix != "us")
|| d.path() == PhysicsTotalDiagnostics::STEP_TIME
|| d.path() == PhysicsTotalDiagnostics::MISCELLANEOUS
{
return None;
}
d.path()
.components()
.next()
.and_then(|c| (c == "avian").then_some(d.value()))
.flatten()
})
.sum();
if timed > 0.0 {
diagnostics.add_measurement(PhysicsTotalDiagnostics::MISCELLANEOUS, || {
(total - timed).max(0.0)
});
}
}