From d57ec2c60b65ac150019c5c262544a6851e5ff70 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Tue, 3 May 2022 19:20:13 +0000 Subject: [PATCH] add `#[reflect(Default)]` to create default value for reflected types (#3733) ### Problem It currently isn't possible to construct the default value of a reflected type. Because of that, it isn't possible to use `add_component` of `ReflectComponent` to add a new component to an entity because you can't know what the initial value should be. ### Solution 1. add `ReflectDefault` type ```rust #[derive(Clone)] pub struct ReflectDefault { default: fn() -> Box, } impl ReflectDefault { pub fn default(&self) -> Box { (self.default)() } } impl FromType for ReflectDefault { fn from_type() -> Self { ReflectDefault { default: || Box::new(T::default()), } } } ``` 2. add `#[reflect(Default)]` to all component types that implement `Default` and are user facing (so not `ComputedSize`, `CubemapVisibleEntities` etc.) This makes it possible to add the default value of a component to an entity without any compile-time information: ```rust fn main() { let mut app = App::new(); app.register_type::(); let type_registry = app.world.get_resource::().unwrap(); let type_registry = type_registry.read(); let camera_registration = type_registry.get(std::any::TypeId::of::()).unwrap(); let reflect_default = camera_registration.data::().unwrap(); let reflect_component = camera_registration .data::() .unwrap() .clone(); let default = reflect_default.default(); drop(type_registry); let entity = app.world.spawn().id(); reflect_component.add_component(&mut app.world, entity, &*default); let camera = app.world.entity(entity).get::().unwrap(); dbg!(&camera); } ``` ### Open questions - should we have `ReflectDefault` or `ReflectFromWorld` or both? --- crates/bevy_core/src/name.rs | 3 ++- crates/bevy_core/src/time/stopwatch.rs | 2 ++ crates/bevy_core/src/time/timer.rs | 3 ++- crates/bevy_pbr/src/alpha.rs | 3 ++- crates/bevy_pbr/src/light.rs | 12 ++++++---- crates/bevy_pbr/src/wireframe.rs | 3 ++- crates/bevy_reflect/src/lib.rs | 3 +++ crates/bevy_reflect/src/std_traits.rs | 23 +++++++++++++++++++ crates/bevy_render/src/camera/camera.rs | 4 ++-- crates/bevy_render/src/camera/projection.rs | 5 ++-- crates/bevy_render/src/view/visibility/mod.rs | 3 ++- .../src/view/visibility/render_layers.rs | 3 ++- crates/bevy_text/src/text.rs | 4 ++-- .../src/components/global_transform.rs | 4 ++-- .../src/components/transform.rs | 3 ++- crates/bevy_ui/src/ui_node.rs | 10 ++++---- crates/bevy_ui/src/widget/button.rs | 3 ++- 17 files changed, 65 insertions(+), 26 deletions(-) create mode 100644 crates/bevy_reflect/src/std_traits.rs diff --git a/crates/bevy_core/src/name.rs b/crates/bevy_core/src/name.rs index 5e98d33631d142..fe320300fd03d5 100644 --- a/crates/bevy_core/src/name.rs +++ b/crates/bevy_core/src/name.rs @@ -1,4 +1,5 @@ use bevy_ecs::{component::Component, reflect::ReflectComponent}; +use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::Reflect; use bevy_utils::AHasher; use std::{ @@ -14,7 +15,7 @@ use std::{ /// as multiple entities can have the same name. [`bevy_ecs::entity::Entity`] should be /// used instead as the default unique identifier. #[derive(Component, Debug, Clone, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct Name { hash: u64, // TODO: Shouldn't be serialized name: Cow<'static, str>, diff --git a/crates/bevy_core/src/time/stopwatch.rs b/crates/bevy_core/src/time/stopwatch.rs index c13f2773918a88..76eb8ea9b583e3 100644 --- a/crates/bevy_core/src/time/stopwatch.rs +++ b/crates/bevy_core/src/time/stopwatch.rs @@ -1,3 +1,4 @@ +use bevy_reflect::prelude::*; use bevy_reflect::Reflect; use bevy_utils::Duration; @@ -23,6 +24,7 @@ use bevy_utils::Duration; /// assert_eq!(stopwatch.elapsed_secs(), 0.0); /// ``` #[derive(Clone, Debug, Default, Reflect)] +#[reflect(Default)] pub struct Stopwatch { elapsed: Duration, paused: bool, diff --git a/crates/bevy_core/src/time/timer.rs b/crates/bevy_core/src/time/timer.rs index 33989c842f82c1..bc894b40d6dc99 100644 --- a/crates/bevy_core/src/time/timer.rs +++ b/crates/bevy_core/src/time/timer.rs @@ -1,5 +1,5 @@ use crate::Stopwatch; -use bevy_reflect::Reflect; +use bevy_reflect::prelude::*; use bevy_utils::Duration; /// Tracks elapsed time. Enters the finished state once `duration` is reached. @@ -10,6 +10,7 @@ use bevy_utils::Duration; /// /// Paused timers will not have elapsed time increased. #[derive(Clone, Debug, Default, Reflect)] +#[reflect(Default)] pub struct Timer { stopwatch: Stopwatch, duration: Duration, diff --git a/crates/bevy_pbr/src/alpha.rs b/crates/bevy_pbr/src/alpha.rs index 9af73fc764011e..ec65a5d113c2d9 100644 --- a/crates/bevy_pbr/src/alpha.rs +++ b/crates/bevy_pbr/src/alpha.rs @@ -1,10 +1,11 @@ use bevy_ecs::{component::Component, reflect::ReflectComponent}; +use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::Reflect; // FIXME: This should probably be part of bevy_render2! /// Alpha mode #[derive(Component, Debug, Reflect, Copy, Clone, PartialEq)] -#[reflect(Component)] +#[reflect(Component, Default)] pub enum AlphaMode { Opaque, /// An alpha cutoff must be supplied where alpha values >= the cutoff diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index 095d112cecff41..5140eae18af186 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -3,7 +3,7 @@ use std::collections::HashSet; use bevy_asset::Assets; use bevy_ecs::prelude::*; use bevy_math::{Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles}; -use bevy_reflect::Reflect; +use bevy_reflect::prelude::*; use bevy_render::{ camera::{Camera, CameraProjection, OrthographicProjection}, color::Color, @@ -41,7 +41,7 @@ use crate::{ /// /// Source: [Wikipedia](https://en.wikipedia.org/wiki/Lumen_(unit)#Lighting) #[derive(Component, Debug, Clone, Copy, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct PointLight { pub color: Color, pub intensity: f32, @@ -113,7 +113,7 @@ impl Default for PointLightShadowMap { /// /// Source: [Wikipedia](https://en.wikipedia.org/wiki/Lux) #[derive(Component, Debug, Clone, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct DirectionalLight { pub color: Color, /// Illuminance in lux @@ -185,10 +185,12 @@ impl Default for AmbientLight { } /// Add this component to make a [`Mesh`](bevy_render::mesh::Mesh) not cast shadows. -#[derive(Component)] +#[derive(Component, Reflect, Default)] +#[reflect(Component, Default)] pub struct NotShadowCaster; /// Add this component to make a [`Mesh`](bevy_render::mesh::Mesh) not receive shadows. -#[derive(Component)] +#[derive(Component, Reflect, Default)] +#[reflect(Component, Default)] pub struct NotShadowReceiver; #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index 54e7f7d6711529..53f39fe0a15ac9 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -4,6 +4,7 @@ use bevy_app::Plugin; use bevy_asset::{load_internal_asset, Handle, HandleUntyped}; use bevy_core_pipeline::Opaque3d; use bevy_ecs::{prelude::*, reflect::ReflectComponent}; +use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::{Reflect, TypeUuid}; use bevy_render::{ mesh::{Mesh, MeshVertexBufferLayout}, @@ -61,7 +62,7 @@ fn extract_wireframes(mut commands: Commands, query: Query Box, +} + +impl ReflectDefault { + pub fn default(&self) -> Box { + (self.default)() + } +} + +impl FromType for ReflectDefault { + fn from_type() -> Self { + ReflectDefault { + default: || Box::new(T::default()), + } + } +} diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index a69892cd22a3a1..fe10ab6be73475 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -21,7 +21,7 @@ use bevy_ecs::{ system::{Commands, ParamSet, Query, Res, ResMut}, }; use bevy_math::{Mat4, UVec2, Vec2, Vec3}; -use bevy_reflect::{Reflect, ReflectDeserialize}; +use bevy_reflect::prelude::*; use bevy_transform::components::GlobalTransform; use bevy_utils::HashSet; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; @@ -29,7 +29,7 @@ use serde::{Deserialize, Serialize}; use wgpu::Extent3d; #[derive(Component, Default, Debug, Reflect, Clone)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct Camera { pub projection_matrix: Mat4, #[reflect(ignore)] diff --git a/crates/bevy_render/src/camera/projection.rs b/crates/bevy_render/src/camera/projection.rs index b0ea170c75f6ef..3f983fa8b33302 100644 --- a/crates/bevy_render/src/camera/projection.rs +++ b/crates/bevy_render/src/camera/projection.rs @@ -1,6 +1,7 @@ use super::DepthCalculation; use bevy_ecs::{component::Component, reflect::ReflectComponent}; use bevy_math::Mat4; +use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::{Reflect, ReflectDeserialize}; use serde::{Deserialize, Serialize}; @@ -12,7 +13,7 @@ pub trait CameraProjection { } #[derive(Component, Debug, Clone, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct PerspectiveProjection { pub fov: f32, pub aspect_ratio: f32, @@ -72,7 +73,7 @@ pub enum ScalingMode { } #[derive(Component, Debug, Clone, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct OrthographicProjection { pub left: f32, pub right: f32, diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index e7cd28c78ce613..478c635572dc96 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -6,6 +6,7 @@ pub use render_layers::*; use bevy_app::{CoreStage, Plugin}; use bevy_asset::{Assets, Handle}; use bevy_ecs::prelude::*; +use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::Reflect; use bevy_transform::components::GlobalTransform; use bevy_transform::TransformSystem; @@ -18,7 +19,7 @@ use crate::{ /// User indication of whether an entity is visible #[derive(Component, Clone, Reflect, Debug)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct Visibility { pub is_visible: bool, } diff --git a/crates/bevy_render/src/view/visibility/render_layers.rs b/crates/bevy_render/src/view/visibility/render_layers.rs index 2d4f5312eba923..c1ac9646a06200 100644 --- a/crates/bevy_render/src/view/visibility/render_layers.rs +++ b/crates/bevy_render/src/view/visibility/render_layers.rs @@ -1,4 +1,5 @@ use bevy_ecs::prelude::{Component, ReflectComponent}; +use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::Reflect; type LayerMask = u32; @@ -20,7 +21,7 @@ pub type Layer = u8; /// /// Entities without this component belong to layer `0`. #[derive(Component, Copy, Clone, Reflect, PartialEq, Eq, PartialOrd, Ord)] -#[reflect(Component, PartialEq)] +#[reflect(Component, Default, PartialEq)] pub struct RenderLayers(LayerMask); impl std::fmt::Debug for RenderLayers { diff --git a/crates/bevy_text/src/text.rs b/crates/bevy_text/src/text.rs index 95a9fa7ee54ff1..02f41ca0e992af 100644 --- a/crates/bevy_text/src/text.rs +++ b/crates/bevy_text/src/text.rs @@ -1,13 +1,13 @@ use bevy_asset::Handle; use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; -use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize}; +use bevy_reflect::{prelude::*, FromReflect}; use bevy_render::color::Color; use serde::{Deserialize, Serialize}; use crate::Font; #[derive(Component, Debug, Default, Clone, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct Text { pub sections: Vec, pub alignment: TextAlignment, diff --git a/crates/bevy_transform/src/components/global_transform.rs b/crates/bevy_transform/src/components/global_transform.rs index c0e0aeac786e49..6bddfead5ad74d 100644 --- a/crates/bevy_transform/src/components/global_transform.rs +++ b/crates/bevy_transform/src/components/global_transform.rs @@ -1,7 +1,7 @@ use super::Transform; use bevy_ecs::{component::Component, reflect::ReflectComponent}; use bevy_math::{const_vec3, Affine3A, Mat3, Mat4, Quat, Vec3}; -use bevy_reflect::Reflect; +use bevy_reflect::prelude::*; use std::ops::Mul; /// Describe the position of an entity relative to the reference frame. @@ -25,7 +25,7 @@ use std::ops::Mul; /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag /// before the [`GlobalTransform`] is updated. #[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] -#[reflect(Component, PartialEq)] +#[reflect(Component, Default, PartialEq)] pub struct GlobalTransform { /// The position of the global transform pub translation: Vec3, diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index 80c80c7f54fbe7..c822336d36c8b9 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -1,6 +1,7 @@ use super::GlobalTransform; use bevy_ecs::{component::Component, reflect::ReflectComponent}; use bevy_math::{const_vec3, Mat3, Mat4, Quat, Vec3}; +use bevy_reflect::prelude::*; use bevy_reflect::Reflect; use std::ops::Mul; @@ -26,7 +27,7 @@ use std::ops::Mul; /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag /// before the [`GlobalTransform`] is updated. #[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] -#[reflect(Component, PartialEq)] +#[reflect(Component, Default, PartialEq)] pub struct Transform { /// Position of the entity. In 2d, the last value of the `Vec3` is used for z-ordering. pub translation: Vec3, diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 0a3d5cc25ff1d5..05d9010b9c6b87 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -2,7 +2,7 @@ use crate::{Size, UiRect}; use bevy_asset::Handle; use bevy_ecs::{prelude::Component, reflect::ReflectComponent}; use bevy_math::Vec2; -use bevy_reflect::{Reflect, ReflectDeserialize}; +use bevy_reflect::prelude::*; use bevy_render::{ color::Color, texture::{Image, DEFAULT_IMAGE_HANDLE}, @@ -12,7 +12,7 @@ use std::ops::{Add, AddAssign}; /// Describes the size of a UI node #[derive(Component, Debug, Clone, Default, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct Node { /// The size of the node as width and height in pixels pub size: Vec2, @@ -68,7 +68,7 @@ impl AddAssign for Val { /// **Note:** Bevy's UI is upside down compared to how Flexbox normally works, to stay consistent with engine paradigms about layouting from /// the upper left corner of the display #[derive(Component, Clone, PartialEq, Debug, Reflect)] -#[reflect(Component, PartialEq)] +#[reflect(Component, Default, PartialEq)] pub struct Style { /// Whether to arrange this node and its children with flexbox layout pub display: Display, @@ -359,7 +359,7 @@ pub struct CalculatedSize { /// The color of the node #[derive(Component, Default, Copy, Clone, Debug, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct UiColor(pub Color); impl From for UiColor { @@ -370,7 +370,7 @@ impl From for UiColor { /// The image of the node #[derive(Component, Clone, Debug, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct UiImage(pub Handle); impl Default for UiImage { diff --git a/crates/bevy_ui/src/widget/button.rs b/crates/bevy_ui/src/widget/button.rs index 9b3c665d4255e9..6c7dced0f3bb09 100644 --- a/crates/bevy_ui/src/widget/button.rs +++ b/crates/bevy_ui/src/widget/button.rs @@ -1,8 +1,9 @@ use bevy_ecs::prelude::Component; use bevy_ecs::reflect::ReflectComponent; +use bevy_reflect::std_traits::ReflectDefault; use bevy_reflect::Reflect; /// Marker struct for buttons #[derive(Component, Debug, Default, Clone, Copy, Reflect)] -#[reflect(Component)] +#[reflect(Component, Default)] pub struct Button;