avian3d/diagnostics/
entity_counters.rs

1use bevy::{diagnostic::DiagnosticPath, prelude::*};
2
3use crate::{
4    dynamics::solver::joints::*, ColliderMarker, PhysicsSchedule, PhysicsStepSet, RigidBody,
5};
6
7use super::{impl_diagnostic_paths, AppDiagnosticsExt, PhysicsDiagnostics};
8
9/// A plugin that adds diagnostics for physics entity counts.
10pub struct PhysicsEntityDiagnosticsPlugin;
11
12impl Plugin for PhysicsEntityDiagnosticsPlugin {
13    fn build(&self, app: &mut App) {
14        // Register diagnostics for physics entity counts.
15        // NOTE: This should be done after the `PhysicsDiagnosticsPlugin` is added.
16        app.register_physics_diagnostics::<PhysicsEntityDiagnostics>();
17
18        app.add_systems(
19            PhysicsSchedule,
20            diagnostic_entity_counts.in_set(PhysicsStepSet::First),
21        );
22    }
23}
24
25/// Diagnostics for physics entity counts.
26#[derive(Resource, Debug, Default, Reflect)]
27#[reflect(Resource, Debug)]
28pub struct PhysicsEntityDiagnostics {
29    /// The number of dynamic bodies.
30    pub dynamic_body_count: u32,
31    /// The number of kinematic bodies.
32    pub kinematic_body_count: u32,
33    /// The number of static bodies.
34    pub static_body_count: u32,
35    /// The number of colliders.
36    pub collider_count: u32,
37    /// The number of joint.
38    pub joint_count: u32,
39}
40
41impl PhysicsDiagnostics for PhysicsEntityDiagnostics {
42    fn counter_paths(&self) -> Vec<(&'static DiagnosticPath, u32)> {
43        vec![
44            (Self::DYNAMIC_BODY_COUNT, self.dynamic_body_count),
45            (Self::KINEMATIC_BODY_COUNT, self.kinematic_body_count),
46            (Self::STATIC_BODY_COUNT, self.static_body_count),
47            (Self::COLLIDER_COUNT, self.collider_count),
48            (Self::JOINT_COUNT, self.joint_count),
49        ]
50    }
51}
52
53impl_diagnostic_paths! {
54    impl PhysicsEntityDiagnostics {
55        DYNAMIC_BODY_COUNT: "avian/entity_count/dynamic_bodies",
56        KINEMATIC_BODY_COUNT: "avian/entity_count/kinematic_bodies",
57        STATIC_BODY_COUNT: "avian/entity_count/static_bodies",
58        COLLIDER_COUNT: "avian/entity_count/colliders",
59        JOINT_COUNT: "avian/entity_count/joints",
60    }
61}
62
63// TODO: This is pretty inefficient.
64fn diagnostic_entity_counts(
65    rigid_bodies_query: Query<&RigidBody>,
66    colliders_query: Query<&ColliderMarker>,
67    fixed_joint_query: Query<&FixedJoint>,
68    prismatic_joint_query: Query<&PrismaticJoint>,
69    distance_joint_query: Query<&DistanceJoint>,
70    revolute_joint_query: Query<&RevoluteJoint>,
71    #[cfg(feature = "3d")] spherical_joint_query: Query<&SphericalJoint>,
72    mut diagnostics: ResMut<PhysicsEntityDiagnostics>,
73) {
74    diagnostics.dynamic_body_count = rigid_bodies_query
75        .iter()
76        .filter(|rb| rb.is_dynamic())
77        .count() as u32;
78    diagnostics.kinematic_body_count = rigid_bodies_query
79        .iter()
80        .filter(|rb| rb.is_kinematic())
81        .count() as u32;
82    diagnostics.static_body_count = rigid_bodies_query
83        .iter()
84        .filter(|rb| rb.is_static())
85        .count() as u32;
86    diagnostics.collider_count = colliders_query.iter().count() as u32;
87    diagnostics.joint_count = fixed_joint_query.iter().count() as u32
88        + prismatic_joint_query.iter().count() as u32
89        + distance_joint_query.iter().count() as u32
90        + revolute_joint_query.iter().count() as u32;
91    #[cfg(feature = "3d")]
92    {
93        diagnostics.joint_count += spherical_joint_query.iter().count() as u32;
94    }
95}