From 9e1845209a8bd7226411cda6063a077e52a32564 Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Mon, 11 Mar 2024 21:38:29 +0100 Subject: [PATCH 01/12] Basic abstraction over dev tools --- crates/bevy_dev_tools/Cargo.toml | 1 + crates/bevy_dev_tools/src/fps_overlay.rs | 9 +++ crates/bevy_dev_tools/src/lib.rs | 89 ++++++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/crates/bevy_dev_tools/Cargo.toml b/crates/bevy_dev_tools/Cargo.toml index 7be2541583148..059386bbedde1 100644 --- a/crates/bevy_dev_tools/Cargo.toml +++ b/crates/bevy_dev_tools/Cargo.toml @@ -29,6 +29,7 @@ bevy_input = { path = "../bevy_input", version = "0.14.0-dev" } # other serde = { version = "1.0", features = ["derive"], optional = true } ron = { version = "0.8.0", optional = true } +uuid = { version = "1.0", features = ["v4"] } [lints] workspace = true diff --git a/crates/bevy_dev_tools/src/fps_overlay.rs b/crates/bevy_dev_tools/src/fps_overlay.rs index 51b8e7886dcf9..070df97e316c8 100644 --- a/crates/bevy_dev_tools/src/fps_overlay.rs +++ b/crates/bevy_dev_tools/src/fps_overlay.rs @@ -13,6 +13,8 @@ use bevy_ecs::{ use bevy_text::{Font, Text, TextSection, TextStyle}; use bevy_ui::node_bundles::TextBundle; +use crate::{DevTool, DevToolId, RegisterDevTool}; + /// A plugin that adds an FPS overlay to the Bevy application. /// /// This plugin will add the [`FrameTimeDiagnosticsPlugin`] if it wasn't added before. @@ -26,6 +28,12 @@ pub struct FpsOverlayPlugin { pub config: FpsOverlayConfig, } +impl FpsOverlayPlugin { + /// [`DevToolId`] of the `FpsOverlayPlugin`. + pub const FPS_OVERLAY_ID: DevToolId = + DevToolId::from_u128(66095722480681667677084752066997432964); +} + impl Plugin for FpsOverlayPlugin { fn build(&self, app: &mut bevy_app::App) { // TODO: Use plugin dependencies, see https://github.com/bevyengine/bevy/issues/69 @@ -33,6 +41,7 @@ impl Plugin for FpsOverlayPlugin { app.add_plugins(FrameTimeDiagnosticsPlugin); } app.insert_resource(self.config.clone()) + .register_dev_tool(DevTool::new(Self::FPS_OVERLAY_ID)) .add_systems(Startup, setup) .add_systems( Update, diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index adad8cec9030b..59f1ca8e71004 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -3,6 +3,9 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] use bevy_app::prelude::*; +use bevy_ecs::system::Resource; +use bevy_utils::HashMap; +use uuid::Uuid; #[cfg(feature = "bevy_ci_testing")] pub mod ci_testing; @@ -45,3 +48,89 @@ impl Plugin for DevToolsPlugin { } } } + +/// Unique identifier for [`DevTool`]. +#[derive(Debug, Hash, Eq, PartialEq, Clone)] +pub struct DevToolId(pub Uuid); + +impl DevToolId { + /// Creates a [`DevToolId`] from u128. + pub const fn from_u128(value: u128) -> DevToolId { + DevToolId(Uuid::from_u128(value)) + } +} + +/// Information about dev tool. +#[derive(Debug)] +pub struct DevTool { + /// Identifier of a dev tool. + pub id: DevToolId, + /// State of the dev tool. + pub is_enabled: bool, +} + +impl DevTool { + /// Creates a new [`DevTool`] from a specified [`DevToolId`]. + /// New tool is enabled by default. + pub fn new(id: DevToolId) -> DevTool { + DevTool { + id, + is_enabled: true, + } + } +} + +/// A collection of [`DevTool`]s. +#[derive(Resource, Default)] +pub struct DevToolsStore { + dev_tools: HashMap, +} + +impl DevToolsStore { + /// Adds a new [`DevTool`]. + /// + /// If possible, prefer calling [`App::register_dev_tool`]. + pub fn add(&mut self, dev_tool: DevTool) { + self.dev_tools.insert(dev_tool.id.clone(), dev_tool); + } + + /// Removes a [`DevTool`]. + pub fn remove(&mut self, id: &DevToolId) { + self.dev_tools.remove(id); + } + + /// Returns a [`DevTool`]. + pub fn get(&self, id: &DevToolId) -> Option<&DevTool> { + self.dev_tools.get(id) + } + + /// Returns a mutable [`DevTool`]. + pub fn get_mut(&mut self, id: &DevToolId) -> Option<&mut DevTool> { + self.dev_tools.get_mut(id) + } + + /// Returns an iterator over all [`DevTool`]s. + pub fn iter(&self) -> impl Iterator { + self.dev_tools.values() + } + + /// Returns an iterator over all [`DevTool`]s, by mutable reference. + pub fn iter_mut(&mut self) -> impl Iterator { + self.dev_tools.values_mut() + } +} + +/// Extend [`App`] with new `register_dev_tool` function. +pub trait RegisterDevTool { + /// Registers a new [`DevTool`]. + fn register_dev_tool(&mut self, dev_tool: DevTool) -> &mut Self; +} + +impl RegisterDevTool for App { + fn register_dev_tool(&mut self, dev_tool: DevTool) -> &mut Self { + self.init_resource::(); + let mut dev_tools = self.world.resource_mut::(); + dev_tools.add(dev_tool); + self + } +} From 2b5cef54597604ccf930eda8c866717ef7adf52a Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Mon, 11 Mar 2024 23:09:39 +0100 Subject: [PATCH 02/12] dev tool helper functions --- crates/bevy_dev_tools/src/lib.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 59f1ca8e71004..893b00dea326e 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -65,8 +65,29 @@ impl DevToolId { pub struct DevTool { /// Identifier of a dev tool. pub id: DevToolId, - /// State of the dev tool. - pub is_enabled: bool, + is_enabled: bool, +} + +impl DevTool { + /// Returns true if [`DevTool`] is enabled. + pub fn is_enabled(&self) -> bool { + self.is_enabled + } + + /// Enables [`DevTool`]. + pub fn enable(&mut self) { + self.is_enabled = true; + } + + /// Disables + pub fn disable(&mut self) { + self.is_enabled = false; + } + + /// Toggles [`DevTool`]. + pub fn toggle(&mut self) { + self.is_enabled = !self.is_enabled; + } } impl DevTool { From dd62c2970f063052cafeaf47201c59398bbca067 Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Mon, 11 Mar 2024 23:10:23 +0100 Subject: [PATCH 03/12] change visibility based on state of the dev tool --- crates/bevy_dev_tools/src/fps_overlay.rs | 28 ++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/crates/bevy_dev_tools/src/fps_overlay.rs b/crates/bevy_dev_tools/src/fps_overlay.rs index 070df97e316c8..5b1e264b035a5 100644 --- a/crates/bevy_dev_tools/src/fps_overlay.rs +++ b/crates/bevy_dev_tools/src/fps_overlay.rs @@ -10,10 +10,11 @@ use bevy_ecs::{ schedule::{common_conditions::resource_changed, IntoSystemConfigs}, system::{Commands, Query, Res, Resource}, }; +use bevy_render::view::Visibility; use bevy_text::{Font, Text, TextSection, TextStyle}; use bevy_ui::node_bundles::TextBundle; -use crate::{DevTool, DevToolId, RegisterDevTool}; +use crate::{DevTool, DevToolId, DevToolsStore, RegisterDevTool}; /// A plugin that adds an FPS overlay to the Bevy application. /// @@ -47,7 +48,12 @@ impl Plugin for FpsOverlayPlugin { Update, ( customize_text.run_if(resource_changed::), - update_text, + change_visibility.run_if(resource_changed::), + update_text.run_if(|dev_tools: Res| { + dev_tools + .get(&Self::FPS_OVERLAY_ID) + .is_some_and(|dev_tool| dev_tool.is_enabled) + }), ), ); } @@ -105,3 +111,21 @@ fn customize_text( } } } + +fn change_visibility( + mut query: Query<&mut Visibility, With>, + dev_tools: Res, +) { + if dev_tools + .get(&FpsOverlayPlugin::FPS_OVERLAY_ID) + .is_some_and(|dev_tool| dev_tool.is_enabled) + { + for mut visibility in query.iter_mut() { + *visibility = Visibility::Visible; + } + } else { + for mut visibility in query.iter_mut() { + *visibility = Visibility::Hidden; + } + } +} From 77f7bfba761c174262f535c8655a661230899ba0 Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Sun, 17 Mar 2024 18:06:57 +0100 Subject: [PATCH 04/12] Update crates/bevy_dev_tools/src/lib.rs Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com> --- crates/bevy_dev_tools/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 893b00dea326e..57f56ce312af9 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -149,8 +149,7 @@ pub trait RegisterDevTool { impl RegisterDevTool for App { fn register_dev_tool(&mut self, dev_tool: DevTool) -> &mut Self { - self.init_resource::(); - let mut dev_tools = self.world.resource_mut::(); + let mut dev_tools = self.world.get_resource_or_insert_with::(Default::default); dev_tools.add(dev_tool); self } From ef686435be5dfd590a458cba844febd1fa45580b Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Sun, 17 Mar 2024 18:08:08 +0100 Subject: [PATCH 05/12] format --- crates/bevy_dev_tools/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 57f56ce312af9..45f04e6291e7c 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -149,7 +149,9 @@ pub trait RegisterDevTool { impl RegisterDevTool for App { fn register_dev_tool(&mut self, dev_tool: DevTool) -> &mut Self { - let mut dev_tools = self.world.get_resource_or_insert_with::(Default::default); + let mut dev_tools = self + .world + .get_resource_or_insert_with::(Default::default); dev_tools.add(dev_tool); self } From 8355a39218079ead44d1b87138da062ea69a0250 Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Sun, 17 Mar 2024 19:38:46 +0100 Subject: [PATCH 06/12] improve docs Co-authored-by: Alice Cecile --- crates/bevy_dev_tools/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 45f04e6291e7c..4fd981ef47149 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -120,17 +120,17 @@ impl DevToolsStore { self.dev_tools.remove(id); } - /// Returns a [`DevTool`]. + /// Returns a reference to the given [`DevTool`] if present. pub fn get(&self, id: &DevToolId) -> Option<&DevTool> { self.dev_tools.get(id) } - /// Returns a mutable [`DevTool`]. + /// Returns a mutable reference to the given [`DevTool`] if present. pub fn get_mut(&mut self, id: &DevToolId) -> Option<&mut DevTool> { self.dev_tools.get_mut(id) } - /// Returns an iterator over all [`DevTool`]s. + /// Returns an iterator over all [`DevTool`]s, by reference. pub fn iter(&self) -> impl Iterator { self.dev_tools.values() } From 8a81cd1cd5bf0fabd72f0e686098c8036fcb5d55 Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Mon, 18 Mar 2024 19:52:34 +0100 Subject: [PATCH 07/12] dev tool trait --- crates/bevy_dev_tools/src/fps_overlay.rs | 8 +++--- crates/bevy_dev_tools/src/lib.rs | 33 ++++++++++++++---------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/crates/bevy_dev_tools/src/fps_overlay.rs b/crates/bevy_dev_tools/src/fps_overlay.rs index 5b1e264b035a5..cbc0503a66da7 100644 --- a/crates/bevy_dev_tools/src/fps_overlay.rs +++ b/crates/bevy_dev_tools/src/fps_overlay.rs @@ -14,7 +14,7 @@ use bevy_render::view::Visibility; use bevy_text::{Font, Text, TextSection, TextStyle}; use bevy_ui::node_bundles::TextBundle; -use crate::{DevTool, DevToolId, DevToolsStore, RegisterDevTool}; +use crate::{DevToolConfig, DevToolId, DevToolsStore, RegisterDevTool, DevTool}; /// A plugin that adds an FPS overlay to the Bevy application. /// @@ -42,7 +42,7 @@ impl Plugin for FpsOverlayPlugin { app.add_plugins(FrameTimeDiagnosticsPlugin); } app.insert_resource(self.config.clone()) - .register_dev_tool(DevTool::new(Self::FPS_OVERLAY_ID)) + .register_dev_tool(DevToolConfig::new(Self::FPS_OVERLAY_ID, FpsOverlayConfig::default())) .add_systems(Startup, setup) .add_systems( Update, @@ -60,12 +60,14 @@ impl Plugin for FpsOverlayPlugin { } /// Configuration options for the FPS overlay. -#[derive(Resource, Clone)] +#[derive(Resource, Clone, Debug)] pub struct FpsOverlayConfig { /// Configuration of text in the overlay. pub text_config: TextStyle, } +impl DevTool for FpsOverlayConfig {} + impl Default for FpsOverlayConfig { fn default() -> Self { FpsOverlayConfig { diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 4fd981ef47149..4762308cf2690 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -2,6 +2,7 @@ //! focused on improving developer experience. #![cfg_attr(docsrs, feature(doc_auto_cfg))] +use std::fmt::Debug; use bevy_app::prelude::*; use bevy_ecs::system::Resource; use bevy_utils::HashMap; @@ -60,15 +61,20 @@ impl DevToolId { } } +/// Trait implemented for every dev tool. +pub trait DevTool: Sync + Send + Debug + 'static {} + /// Information about dev tool. #[derive(Debug)] -pub struct DevTool { +pub struct DevToolConfig { /// Identifier of a dev tool. pub id: DevToolId, + /// Tool specific configuration. + pub tool_config: Box, is_enabled: bool, } -impl DevTool { +impl DevToolConfig { /// Returns true if [`DevTool`] is enabled. pub fn is_enabled(&self) -> bool { self.is_enabled @@ -90,12 +96,13 @@ impl DevTool { } } -impl DevTool { +impl DevToolConfig { /// Creates a new [`DevTool`] from a specified [`DevToolId`]. /// New tool is enabled by default. - pub fn new(id: DevToolId) -> DevTool { - DevTool { + pub fn new(id: DevToolId, tool_config: impl DevTool) -> DevToolConfig { + DevToolConfig { id, + tool_config: Box::new(tool_config), is_enabled: true, } } @@ -104,14 +111,14 @@ impl DevTool { /// A collection of [`DevTool`]s. #[derive(Resource, Default)] pub struct DevToolsStore { - dev_tools: HashMap, + dev_tools: HashMap, } impl DevToolsStore { /// Adds a new [`DevTool`]. /// /// If possible, prefer calling [`App::register_dev_tool`]. - pub fn add(&mut self, dev_tool: DevTool) { + pub fn add(&mut self, dev_tool: DevToolConfig) { self.dev_tools.insert(dev_tool.id.clone(), dev_tool); } @@ -121,22 +128,22 @@ impl DevToolsStore { } /// Returns a reference to the given [`DevTool`] if present. - pub fn get(&self, id: &DevToolId) -> Option<&DevTool> { + pub fn get(&self, id: &DevToolId) -> Option<&DevToolConfig> { self.dev_tools.get(id) } /// Returns a mutable reference to the given [`DevTool`] if present. - pub fn get_mut(&mut self, id: &DevToolId) -> Option<&mut DevTool> { + pub fn get_mut(&mut self, id: &DevToolId) -> Option<&mut DevToolConfig> { self.dev_tools.get_mut(id) } /// Returns an iterator over all [`DevTool`]s, by reference. - pub fn iter(&self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator { self.dev_tools.values() } /// Returns an iterator over all [`DevTool`]s, by mutable reference. - pub fn iter_mut(&mut self) -> impl Iterator { + pub fn iter_mut(&mut self) -> impl Iterator { self.dev_tools.values_mut() } } @@ -144,11 +151,11 @@ impl DevToolsStore { /// Extend [`App`] with new `register_dev_tool` function. pub trait RegisterDevTool { /// Registers a new [`DevTool`]. - fn register_dev_tool(&mut self, dev_tool: DevTool) -> &mut Self; + fn register_dev_tool(&mut self, dev_tool: DevToolConfig) -> &mut Self; } impl RegisterDevTool for App { - fn register_dev_tool(&mut self, dev_tool: DevTool) -> &mut Self { + fn register_dev_tool(&mut self, dev_tool: DevToolConfig) -> &mut Self { let mut dev_tools = self .world .get_resource_or_insert_with::(Default::default); From e2f8f89b0bb9fa3b2760019025d0809a45ca030d Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Mon, 18 Mar 2024 19:58:19 +0100 Subject: [PATCH 08/12] use typeid instead of uuid --- crates/bevy_dev_tools/Cargo.toml | 1 - crates/bevy_dev_tools/src/fps_overlay.rs | 19 ++++++++-------- crates/bevy_dev_tools/src/lib.rs | 28 +++++++----------------- 3 files changed, 17 insertions(+), 31 deletions(-) diff --git a/crates/bevy_dev_tools/Cargo.toml b/crates/bevy_dev_tools/Cargo.toml index 059386bbedde1..7be2541583148 100644 --- a/crates/bevy_dev_tools/Cargo.toml +++ b/crates/bevy_dev_tools/Cargo.toml @@ -29,7 +29,6 @@ bevy_input = { path = "../bevy_input", version = "0.14.0-dev" } # other serde = { version = "1.0", features = ["derive"], optional = true } ron = { version = "0.8.0", optional = true } -uuid = { version = "1.0", features = ["v4"] } [lints] workspace = true diff --git a/crates/bevy_dev_tools/src/fps_overlay.rs b/crates/bevy_dev_tools/src/fps_overlay.rs index cbc0503a66da7..25dff49018b0a 100644 --- a/crates/bevy_dev_tools/src/fps_overlay.rs +++ b/crates/bevy_dev_tools/src/fps_overlay.rs @@ -1,5 +1,7 @@ //! Module containing logic for FPS overlay. +use std::any::TypeId; + use bevy_app::{Plugin, Startup, Update}; use bevy_asset::Handle; use bevy_color::Color; @@ -14,7 +16,7 @@ use bevy_render::view::Visibility; use bevy_text::{Font, Text, TextSection, TextStyle}; use bevy_ui::node_bundles::TextBundle; -use crate::{DevToolConfig, DevToolId, DevToolsStore, RegisterDevTool, DevTool}; +use crate::{DevTool, DevToolConfig, DevToolsStore, RegisterDevTool}; /// A plugin that adds an FPS overlay to the Bevy application. /// @@ -29,12 +31,6 @@ pub struct FpsOverlayPlugin { pub config: FpsOverlayConfig, } -impl FpsOverlayPlugin { - /// [`DevToolId`] of the `FpsOverlayPlugin`. - pub const FPS_OVERLAY_ID: DevToolId = - DevToolId::from_u128(66095722480681667677084752066997432964); -} - impl Plugin for FpsOverlayPlugin { fn build(&self, app: &mut bevy_app::App) { // TODO: Use plugin dependencies, see https://github.com/bevyengine/bevy/issues/69 @@ -42,7 +38,10 @@ impl Plugin for FpsOverlayPlugin { app.add_plugins(FrameTimeDiagnosticsPlugin); } app.insert_resource(self.config.clone()) - .register_dev_tool(DevToolConfig::new(Self::FPS_OVERLAY_ID, FpsOverlayConfig::default())) + .register_dev_tool(DevToolConfig::new( + TypeId::of::(), + FpsOverlayConfig::default(), + )) .add_systems(Startup, setup) .add_systems( Update, @@ -51,7 +50,7 @@ impl Plugin for FpsOverlayPlugin { change_visibility.run_if(resource_changed::), update_text.run_if(|dev_tools: Res| { dev_tools - .get(&Self::FPS_OVERLAY_ID) + .get(&TypeId::of::()) .is_some_and(|dev_tool| dev_tool.is_enabled) }), ), @@ -119,7 +118,7 @@ fn change_visibility( dev_tools: Res, ) { if dev_tools - .get(&FpsOverlayPlugin::FPS_OVERLAY_ID) + .get(&TypeId::of::()) .is_some_and(|dev_tool| dev_tool.is_enabled) { for mut visibility in query.iter_mut() { diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 4762308cf2690..9cdfa83788cbc 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -2,11 +2,10 @@ //! focused on improving developer experience. #![cfg_attr(docsrs, feature(doc_auto_cfg))] -use std::fmt::Debug; use bevy_app::prelude::*; use bevy_ecs::system::Resource; use bevy_utils::HashMap; -use uuid::Uuid; +use std::{any::TypeId, fmt::Debug}; #[cfg(feature = "bevy_ci_testing")] pub mod ci_testing; @@ -50,17 +49,6 @@ impl Plugin for DevToolsPlugin { } } -/// Unique identifier for [`DevTool`]. -#[derive(Debug, Hash, Eq, PartialEq, Clone)] -pub struct DevToolId(pub Uuid); - -impl DevToolId { - /// Creates a [`DevToolId`] from u128. - pub const fn from_u128(value: u128) -> DevToolId { - DevToolId(Uuid::from_u128(value)) - } -} - /// Trait implemented for every dev tool. pub trait DevTool: Sync + Send + Debug + 'static {} @@ -68,7 +56,7 @@ pub trait DevTool: Sync + Send + Debug + 'static {} #[derive(Debug)] pub struct DevToolConfig { /// Identifier of a dev tool. - pub id: DevToolId, + pub id: TypeId, /// Tool specific configuration. pub tool_config: Box, is_enabled: bool, @@ -99,7 +87,7 @@ impl DevToolConfig { impl DevToolConfig { /// Creates a new [`DevTool`] from a specified [`DevToolId`]. /// New tool is enabled by default. - pub fn new(id: DevToolId, tool_config: impl DevTool) -> DevToolConfig { + pub fn new(id: TypeId, tool_config: impl DevTool) -> DevToolConfig { DevToolConfig { id, tool_config: Box::new(tool_config), @@ -109,9 +97,9 @@ impl DevToolConfig { } /// A collection of [`DevTool`]s. -#[derive(Resource, Default)] +#[derive(Resource, Default, Debug)] pub struct DevToolsStore { - dev_tools: HashMap, + dev_tools: HashMap, } impl DevToolsStore { @@ -123,17 +111,17 @@ impl DevToolsStore { } /// Removes a [`DevTool`]. - pub fn remove(&mut self, id: &DevToolId) { + pub fn remove(&mut self, id: &TypeId) { self.dev_tools.remove(id); } /// Returns a reference to the given [`DevTool`] if present. - pub fn get(&self, id: &DevToolId) -> Option<&DevToolConfig> { + pub fn get(&self, id: &TypeId) -> Option<&DevToolConfig> { self.dev_tools.get(id) } /// Returns a mutable reference to the given [`DevTool`] if present. - pub fn get_mut(&mut self, id: &DevToolId) -> Option<&mut DevToolConfig> { + pub fn get_mut(&mut self, id: &TypeId) -> Option<&mut DevToolConfig> { self.dev_tools.get_mut(id) } From 93e697f096f20389cbc4da975946ba0939803a14 Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Mon, 18 Mar 2024 22:00:27 +0100 Subject: [PATCH 09/12] add init_dev_tool and insert_dev_tool --- crates/bevy_dev_tools/src/fps_overlay.rs | 7 ++----- crates/bevy_dev_tools/src/lib.rs | 24 ++++++++++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/crates/bevy_dev_tools/src/fps_overlay.rs b/crates/bevy_dev_tools/src/fps_overlay.rs index 25dff49018b0a..3ea7dcf048a44 100644 --- a/crates/bevy_dev_tools/src/fps_overlay.rs +++ b/crates/bevy_dev_tools/src/fps_overlay.rs @@ -16,7 +16,7 @@ use bevy_render::view::Visibility; use bevy_text::{Font, Text, TextSection, TextStyle}; use bevy_ui::node_bundles::TextBundle; -use crate::{DevTool, DevToolConfig, DevToolsStore, RegisterDevTool}; +use crate::{DevTool, DevToolApp, DevToolsStore}; /// A plugin that adds an FPS overlay to the Bevy application. /// @@ -38,10 +38,7 @@ impl Plugin for FpsOverlayPlugin { app.add_plugins(FrameTimeDiagnosticsPlugin); } app.insert_resource(self.config.clone()) - .register_dev_tool(DevToolConfig::new( - TypeId::of::(), - FpsOverlayConfig::default(), - )) + .init_dev_tool::() .add_systems(Startup, setup) .add_systems( Update, diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 9cdfa83788cbc..742ece02ebce1 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -136,14 +136,26 @@ impl DevToolsStore { } } -/// Extend [`App`] with new `register_dev_tool` function. -pub trait RegisterDevTool { - /// Registers a new [`DevTool`]. - fn register_dev_tool(&mut self, dev_tool: DevToolConfig) -> &mut Self; +/// Extends [`App`] with new `init_dev_tool` and `insert_dev_tool` functions. +pub trait DevToolApp { + /// Initialize a new [`DevTool`]. + fn init_dev_tool(&mut self) -> &mut Self; + /// Insert a new [`DevTool`] with configuration. + fn insert_dev_tool(&mut self, value: D) -> &mut Self; } -impl RegisterDevTool for App { - fn register_dev_tool(&mut self, dev_tool: DevToolConfig) -> &mut Self { +impl DevToolApp for App { + fn init_dev_tool(&mut self) -> &mut Self { + let dev_tool = DevToolConfig::new(TypeId::of::(), D::default()); + let mut dev_tools = self + .world + .get_resource_or_insert_with::(Default::default); + dev_tools.add(dev_tool); + self + } + + fn insert_dev_tool(&mut self, value: D) -> &mut Self { + let dev_tool = DevToolConfig::new(TypeId::of::(), value); let mut dev_tools = self .world .get_resource_or_insert_with::(Default::default); From 1ad34693a33b344c359274d1671edc760b9c8fc7 Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Mon, 18 Mar 2024 22:36:39 +0100 Subject: [PATCH 10/12] use config from DevToolConfig instead of a resource in fps overlay --- crates/bevy_dev_tools/src/fps_overlay.rs | 51 ++++++++++++++++-------- crates/bevy_dev_tools/src/lib.rs | 24 +++++++++-- examples/dev_tools/fps_overlay.rs | 25 +++++++++--- 3 files changed, 76 insertions(+), 24 deletions(-) diff --git a/crates/bevy_dev_tools/src/fps_overlay.rs b/crates/bevy_dev_tools/src/fps_overlay.rs index 3ea7dcf048a44..69d0152bc3715 100644 --- a/crates/bevy_dev_tools/src/fps_overlay.rs +++ b/crates/bevy_dev_tools/src/fps_overlay.rs @@ -10,11 +10,12 @@ use bevy_ecs::{ component::Component, query::With, schedule::{common_conditions::resource_changed, IntoSystemConfigs}, - system::{Commands, Query, Res, Resource}, + system::{Commands, Query, Res}, }; use bevy_render::view::Visibility; use bevy_text::{Font, Text, TextSection, TextStyle}; use bevy_ui::node_bundles::TextBundle; +use bevy_utils::warn_once; use crate::{DevTool, DevToolApp, DevToolsStore}; @@ -27,7 +28,7 @@ use crate::{DevTool, DevToolApp, DevToolsStore}; /// - **Metal**: setting env variable `MTL_HUD_ENABLED=1` #[derive(Default)] pub struct FpsOverlayPlugin { - /// Starting configuration of overlay, this can be later be changed through [`FpsOverlayConfig`] resource. + /// Starting configuration of overlay, this can be later be changed through [`DevToolsStore`] resource. pub config: FpsOverlayConfig, } @@ -37,15 +38,13 @@ impl Plugin for FpsOverlayPlugin { if !app.is_plugin_added::() { app.add_plugins(FrameTimeDiagnosticsPlugin); } - app.insert_resource(self.config.clone()) - .init_dev_tool::() + app.insert_dev_tool(self.config.clone()) .add_systems(Startup, setup) .add_systems( Update, ( - customize_text.run_if(resource_changed::), change_visibility.run_if(resource_changed::), - update_text.run_if(|dev_tools: Res| { + (customize_text, update_text).run_if(|dev_tools: Res| { dev_tools .get(&TypeId::of::()) .is_some_and(|dev_tool| dev_tool.is_enabled) @@ -56,13 +55,20 @@ impl Plugin for FpsOverlayPlugin { } /// Configuration options for the FPS overlay. -#[derive(Resource, Clone, Debug)] +#[derive(Clone, Debug)] pub struct FpsOverlayConfig { /// Configuration of text in the overlay. pub text_config: TextStyle, } -impl DevTool for FpsOverlayConfig {} +impl DevTool for FpsOverlayConfig { + fn as_any(&self) -> &dyn std::any::Any { + self + } + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self + } +} impl Default for FpsOverlayConfig { fn default() -> Self { @@ -79,11 +85,19 @@ impl Default for FpsOverlayConfig { #[derive(Component)] struct FpsText; -fn setup(mut commands: Commands, overlay_config: Res) { +fn setup(mut commands: Commands, dev_tools: Res) { + let Some(dev_tool) = dev_tools.get(&TypeId::of::()) else { + warn_once!("Dev tool with TypeId of FpsOverlayConfig does not exist in DevToolsStore. Fps overlay won't be created"); + return; + }; + let Some(tool_config) = dev_tool.get_tool_config::() else { + warn_once!("Failed to get tool config from dev tool. Fps overlay won't be created"); + return; + }; commands.spawn(( TextBundle::from_sections([ - TextSection::new("FPS: ", overlay_config.text_config.clone()), - TextSection::from_style(overlay_config.text_config.clone()), + TextSection::new("FPS: ", tool_config.text_config.clone()), + TextSection::from_style(tool_config.text_config.clone()), ]), FpsText, )); @@ -99,13 +113,18 @@ fn update_text(diagnostic: Res, mut query: Query<&mut Text, Wi } } -fn customize_text( - overlay_config: Res, - mut query: Query<&mut Text, With>, -) { +fn customize_text(dev_tools: Res, mut query: Query<&mut Text, With>) { for mut text in &mut query { for section in text.sections.iter_mut() { - section.style = overlay_config.text_config.clone(); + let Some(dev_tool) = dev_tools.get(&TypeId::of::()) else { + warn_once!("Dev tool with TypeId of FpsOverlayConfig does not exist in DevToolsStore. You won't be able to customize the overlay"); + return; + }; + let Some(tool_config) = dev_tool.get_tool_config::() else { + warn_once!("Failed to get tool config from dev tool. Fps overlay won't be created. You won't be able to customize the overlay"); + return; + }; + section.style = tool_config.text_config.clone(); } } } diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 742ece02ebce1..c03250745452f 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -5,7 +5,10 @@ use bevy_app::prelude::*; use bevy_ecs::system::Resource; use bevy_utils::HashMap; -use std::{any::TypeId, fmt::Debug}; +use std::{ + any::{Any, TypeId}, + fmt::Debug, +}; #[cfg(feature = "bevy_ci_testing")] pub mod ci_testing; @@ -50,7 +53,12 @@ impl Plugin for DevToolsPlugin { } /// Trait implemented for every dev tool. -pub trait DevTool: Sync + Send + Debug + 'static {} +pub trait DevTool: Sync + Send + Debug + 'static { + /// Casts to `&dyn Any`. + fn as_any(&self) -> &dyn Any; + /// Casts to `&mut dyn Any`. + fn as_any_mut(&mut self) -> &mut dyn Any; +} /// Information about dev tool. #[derive(Debug)] @@ -58,7 +66,7 @@ pub struct DevToolConfig { /// Identifier of a dev tool. pub id: TypeId, /// Tool specific configuration. - pub tool_config: Box, + tool_config: Box, is_enabled: bool, } @@ -94,6 +102,16 @@ impl DevToolConfig { is_enabled: true, } } + + /// Returns a tool specific configuration. + pub fn get_tool_config(&self) -> Option<&D> { + self.tool_config.as_any().downcast_ref::() + } + + /// Returns a mutable tool specific configuration. + pub fn get_tool_config_mut(&mut self) -> Option<&mut D> { + self.tool_config.as_any_mut().downcast_mut::() + } } /// A collection of [`DevTool`]s. diff --git a/examples/dev_tools/fps_overlay.rs b/examples/dev_tools/fps_overlay.rs index e7f4cada95462..29cfb82946614 100644 --- a/examples/dev_tools/fps_overlay.rs +++ b/examples/dev_tools/fps_overlay.rs @@ -1,7 +1,12 @@ //! Showcase how to use and configure FPS overlay. +use std::any::TypeId; + use bevy::{ - dev_tools::fps_overlay::{FpsOverlayConfig, FpsOverlayPlugin}, + dev_tools::{ + fps_overlay::{FpsOverlayConfig, FpsOverlayPlugin}, + DevToolsStore, + }, prelude::*, }; @@ -54,12 +59,22 @@ fn setup(mut commands: Commands) { ); } -fn customize_config(input: Res>, mut overlay: ResMut) { +fn customize_config(input: Res>, mut dev_tools: ResMut) { + // We try to get mutable reference to fps overlay dev tool. Otherwise we don't do anything + let Some(dev_tool) = dev_tools.get_mut(&TypeId::of::()) else { + return; + }; + + // We try to access configuration struct that is specific to this dev tool. + let Some(tool_config) = dev_tool.get_tool_config_mut::() else { + return; + }; + if input.just_pressed(KeyCode::Digit1) { - // Changing resource will affect overlay - overlay.text_config.color = Color::srgb(1.0, 0.0, 0.0); + // Changing tool_config will affect overlay + tool_config.text_config.color = Color::srgb(1.0, 0.0, 0.0); } if input.just_pressed(KeyCode::Digit2) { - overlay.text_config.font_size -= 2.0; + tool_config.text_config.font_size -= 2.0; } } From d99985040d6e924ec28ad1b32ff6495fa8441b86 Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Mon, 18 Mar 2024 22:48:00 +0100 Subject: [PATCH 11/12] update docs and remove .clone() --- crates/bevy_dev_tools/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index c03250745452f..0bfd96807a674 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -93,7 +93,7 @@ impl DevToolConfig { } impl DevToolConfig { - /// Creates a new [`DevTool`] from a specified [`DevToolId`]. + /// Creates a new [`DevTool`] from a specified [`TypeId`]. /// New tool is enabled by default. pub fn new(id: TypeId, tool_config: impl DevTool) -> DevToolConfig { DevToolConfig { @@ -123,9 +123,9 @@ pub struct DevToolsStore { impl DevToolsStore { /// Adds a new [`DevTool`]. /// - /// If possible, prefer calling [`App::register_dev_tool`]. + /// If possible, prefer calling [`App::init_dev_tool`] or [`App::insert_dev_tool`]. pub fn add(&mut self, dev_tool: DevToolConfig) { - self.dev_tools.insert(dev_tool.id.clone(), dev_tool); + self.dev_tools.insert(dev_tool.id, dev_tool); } /// Removes a [`DevTool`]. From 8e6eab91f4ff41b23e0597cb7159b8c8fd5574a5 Mon Sep 17 00:00:00 2001 From: Mateusz Wachowiak Date: Mon, 18 Mar 2024 22:54:06 +0100 Subject: [PATCH 12/12] add Reflect bound to DevTool trait --- crates/bevy_dev_tools/Cargo.toml | 1 + crates/bevy_dev_tools/src/fps_overlay.rs | 12 +++--------- crates/bevy_dev_tools/src/lib.rs | 13 +++---------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/crates/bevy_dev_tools/Cargo.toml b/crates/bevy_dev_tools/Cargo.toml index 7be2541583148..290772f150c7f 100644 --- a/crates/bevy_dev_tools/Cargo.toml +++ b/crates/bevy_dev_tools/Cargo.toml @@ -25,6 +25,7 @@ bevy_text = { path = "../bevy_text", version = "0.14.0-dev" } bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.14.0-dev" } bevy_color = { path = "../bevy_color", version = "0.14.0-dev" } bevy_input = { path = "../bevy_input", version = "0.14.0-dev" } +bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev" } # other serde = { version = "1.0", features = ["derive"], optional = true } diff --git a/crates/bevy_dev_tools/src/fps_overlay.rs b/crates/bevy_dev_tools/src/fps_overlay.rs index 69d0152bc3715..4092a228f41ab 100644 --- a/crates/bevy_dev_tools/src/fps_overlay.rs +++ b/crates/bevy_dev_tools/src/fps_overlay.rs @@ -12,6 +12,7 @@ use bevy_ecs::{ schedule::{common_conditions::resource_changed, IntoSystemConfigs}, system::{Commands, Query, Res}, }; +use bevy_reflect::Reflect; use bevy_render::view::Visibility; use bevy_text::{Font, Text, TextSection, TextStyle}; use bevy_ui::node_bundles::TextBundle; @@ -55,20 +56,13 @@ impl Plugin for FpsOverlayPlugin { } /// Configuration options for the FPS overlay. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Reflect)] pub struct FpsOverlayConfig { /// Configuration of text in the overlay. pub text_config: TextStyle, } -impl DevTool for FpsOverlayConfig { - fn as_any(&self) -> &dyn std::any::Any { - self - } - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } -} +impl DevTool for FpsOverlayConfig {} impl Default for FpsOverlayConfig { fn default() -> Self { diff --git a/crates/bevy_dev_tools/src/lib.rs b/crates/bevy_dev_tools/src/lib.rs index 0bfd96807a674..bb1af17d0177f 100644 --- a/crates/bevy_dev_tools/src/lib.rs +++ b/crates/bevy_dev_tools/src/lib.rs @@ -4,11 +4,9 @@ use bevy_app::prelude::*; use bevy_ecs::system::Resource; +use bevy_reflect::Reflect; use bevy_utils::HashMap; -use std::{ - any::{Any, TypeId}, - fmt::Debug, -}; +use std::{any::TypeId, fmt::Debug}; #[cfg(feature = "bevy_ci_testing")] pub mod ci_testing; @@ -53,12 +51,7 @@ impl Plugin for DevToolsPlugin { } /// Trait implemented for every dev tool. -pub trait DevTool: Sync + Send + Debug + 'static { - /// Casts to `&dyn Any`. - fn as_any(&self) -> &dyn Any; - /// Casts to `&mut dyn Any`. - fn as_any_mut(&mut self) -> &mut dyn Any; -} +pub trait DevTool: Sync + Send + Debug + Reflect + 'static {} /// Information about dev tool. #[derive(Debug)]