Skip to content

Commit d57ec2c

Browse files
jakobhellermannItsDoot
authored andcommitted
add #[reflect(Default)] to create default value for reflected types (bevyengine#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<dyn Reflect>, } impl ReflectDefault { pub fn default(&self) -> Box<dyn Reflect> { (self.default)() } } impl<T: Reflect + Default> FromType<T> 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::<Camera>(); let type_registry = app.world.get_resource::<TypeRegistry>().unwrap(); let type_registry = type_registry.read(); let camera_registration = type_registry.get(std::any::TypeId::of::<Camera>()).unwrap(); let reflect_default = camera_registration.data::<ReflectDefault>().unwrap(); let reflect_component = camera_registration .data::<ReflectComponent>() .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::<Camera>().unwrap(); dbg!(&camera); } ``` ### Open questions - should we have `ReflectDefault` or `ReflectFromWorld` or both?
1 parent 22f899b commit d57ec2c

File tree

17 files changed

+65
-26
lines changed

17 files changed

+65
-26
lines changed

crates/bevy_core/src/name.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use bevy_ecs::{component::Component, reflect::ReflectComponent};
2+
use bevy_reflect::std_traits::ReflectDefault;
23
use bevy_reflect::Reflect;
34
use bevy_utils::AHasher;
45
use std::{
@@ -14,7 +15,7 @@ use std::{
1415
/// as multiple entities can have the same name. [`bevy_ecs::entity::Entity`] should be
1516
/// used instead as the default unique identifier.
1617
#[derive(Component, Debug, Clone, Reflect)]
17-
#[reflect(Component)]
18+
#[reflect(Component, Default)]
1819
pub struct Name {
1920
hash: u64, // TODO: Shouldn't be serialized
2021
name: Cow<'static, str>,

crates/bevy_core/src/time/stopwatch.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use bevy_reflect::prelude::*;
12
use bevy_reflect::Reflect;
23
use bevy_utils::Duration;
34

@@ -23,6 +24,7 @@ use bevy_utils::Duration;
2324
/// assert_eq!(stopwatch.elapsed_secs(), 0.0);
2425
/// ```
2526
#[derive(Clone, Debug, Default, Reflect)]
27+
#[reflect(Default)]
2628
pub struct Stopwatch {
2729
elapsed: Duration,
2830
paused: bool,

crates/bevy_core/src/time/timer.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::Stopwatch;
2-
use bevy_reflect::Reflect;
2+
use bevy_reflect::prelude::*;
33
use bevy_utils::Duration;
44

55
/// Tracks elapsed time. Enters the finished state once `duration` is reached.
@@ -10,6 +10,7 @@ use bevy_utils::Duration;
1010
///
1111
/// Paused timers will not have elapsed time increased.
1212
#[derive(Clone, Debug, Default, Reflect)]
13+
#[reflect(Default)]
1314
pub struct Timer {
1415
stopwatch: Stopwatch,
1516
duration: Duration,

crates/bevy_pbr/src/alpha.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use bevy_ecs::{component::Component, reflect::ReflectComponent};
2+
use bevy_reflect::std_traits::ReflectDefault;
23
use bevy_reflect::Reflect;
34

45
// FIXME: This should probably be part of bevy_render2!
56
/// Alpha mode
67
#[derive(Component, Debug, Reflect, Copy, Clone, PartialEq)]
7-
#[reflect(Component)]
8+
#[reflect(Component, Default)]
89
pub enum AlphaMode {
910
Opaque,
1011
/// An alpha cutoff must be supplied where alpha values >= the cutoff

crates/bevy_pbr/src/light.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::HashSet;
33
use bevy_asset::Assets;
44
use bevy_ecs::prelude::*;
55
use bevy_math::{Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles};
6-
use bevy_reflect::Reflect;
6+
use bevy_reflect::prelude::*;
77
use bevy_render::{
88
camera::{Camera, CameraProjection, OrthographicProjection},
99
color::Color,
@@ -41,7 +41,7 @@ use crate::{
4141
///
4242
/// Source: [Wikipedia](https://en.wikipedia.org/wiki/Lumen_(unit)#Lighting)
4343
#[derive(Component, Debug, Clone, Copy, Reflect)]
44-
#[reflect(Component)]
44+
#[reflect(Component, Default)]
4545
pub struct PointLight {
4646
pub color: Color,
4747
pub intensity: f32,
@@ -113,7 +113,7 @@ impl Default for PointLightShadowMap {
113113
///
114114
/// Source: [Wikipedia](https://en.wikipedia.org/wiki/Lux)
115115
#[derive(Component, Debug, Clone, Reflect)]
116-
#[reflect(Component)]
116+
#[reflect(Component, Default)]
117117
pub struct DirectionalLight {
118118
pub color: Color,
119119
/// Illuminance in lux
@@ -185,10 +185,12 @@ impl Default for AmbientLight {
185185
}
186186

187187
/// Add this component to make a [`Mesh`](bevy_render::mesh::Mesh) not cast shadows.
188-
#[derive(Component)]
188+
#[derive(Component, Reflect, Default)]
189+
#[reflect(Component, Default)]
189190
pub struct NotShadowCaster;
190191
/// Add this component to make a [`Mesh`](bevy_render::mesh::Mesh) not receive shadows.
191-
#[derive(Component)]
192+
#[derive(Component, Reflect, Default)]
193+
#[reflect(Component, Default)]
192194
pub struct NotShadowReceiver;
193195

194196
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)]

crates/bevy_pbr/src/wireframe.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use bevy_app::Plugin;
44
use bevy_asset::{load_internal_asset, Handle, HandleUntyped};
55
use bevy_core_pipeline::Opaque3d;
66
use bevy_ecs::{prelude::*, reflect::ReflectComponent};
7+
use bevy_reflect::std_traits::ReflectDefault;
78
use bevy_reflect::{Reflect, TypeUuid};
89
use bevy_render::{
910
mesh::{Mesh, MeshVertexBufferLayout},
@@ -61,7 +62,7 @@ fn extract_wireframes(mut commands: Commands, query: Query<Entity, With<Wirefram
6162

6263
/// Controls whether an entity should rendered in wireframe-mode if the [`WireframePlugin`] is enabled
6364
#[derive(Component, Debug, Clone, Default, Reflect)]
64-
#[reflect(Component)]
65+
#[reflect(Component, Default)]
6566
pub struct Wireframe;
6667

6768
#[derive(Debug, Clone, Default)]

crates/bevy_reflect/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ mod impls {
2424
}
2525

2626
pub mod serde;
27+
pub mod std_traits;
28+
2729
pub mod prelude {
30+
pub use crate::std_traits::*;
2831
#[doc(hidden)]
2932
pub use crate::{
3033
reflect_trait, GetField, GetTupleStructField, Reflect, ReflectDeserialize, Struct,

crates/bevy_reflect/src/std_traits.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use crate::{FromType, Reflect};
2+
3+
/// A struct used to provide the default value of a type.
4+
///
5+
/// A [`ReflectDefault`] for type `T` can be obtained via [`FromType::from_type`].
6+
#[derive(Clone)]
7+
pub struct ReflectDefault {
8+
default: fn() -> Box<dyn Reflect>,
9+
}
10+
11+
impl ReflectDefault {
12+
pub fn default(&self) -> Box<dyn Reflect> {
13+
(self.default)()
14+
}
15+
}
16+
17+
impl<T: Reflect + Default> FromType<T> for ReflectDefault {
18+
fn from_type() -> Self {
19+
ReflectDefault {
20+
default: || Box::new(T::default()),
21+
}
22+
}
23+
}

crates/bevy_render/src/camera/camera.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ use bevy_ecs::{
2121
system::{Commands, ParamSet, Query, Res, ResMut},
2222
};
2323
use bevy_math::{Mat4, UVec2, Vec2, Vec3};
24-
use bevy_reflect::{Reflect, ReflectDeserialize};
24+
use bevy_reflect::prelude::*;
2525
use bevy_transform::components::GlobalTransform;
2626
use bevy_utils::HashSet;
2727
use bevy_window::{WindowCreated, WindowId, WindowResized, Windows};
2828
use serde::{Deserialize, Serialize};
2929
use wgpu::Extent3d;
3030

3131
#[derive(Component, Default, Debug, Reflect, Clone)]
32-
#[reflect(Component)]
32+
#[reflect(Component, Default)]
3333
pub struct Camera {
3434
pub projection_matrix: Mat4,
3535
#[reflect(ignore)]

crates/bevy_render/src/camera/projection.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::DepthCalculation;
22
use bevy_ecs::{component::Component, reflect::ReflectComponent};
33
use bevy_math::Mat4;
4+
use bevy_reflect::std_traits::ReflectDefault;
45
use bevy_reflect::{Reflect, ReflectDeserialize};
56
use serde::{Deserialize, Serialize};
67

@@ -12,7 +13,7 @@ pub trait CameraProjection {
1213
}
1314

1415
#[derive(Component, Debug, Clone, Reflect)]
15-
#[reflect(Component)]
16+
#[reflect(Component, Default)]
1617
pub struct PerspectiveProjection {
1718
pub fov: f32,
1819
pub aspect_ratio: f32,
@@ -72,7 +73,7 @@ pub enum ScalingMode {
7273
}
7374

7475
#[derive(Component, Debug, Clone, Reflect)]
75-
#[reflect(Component)]
76+
#[reflect(Component, Default)]
7677
pub struct OrthographicProjection {
7778
pub left: f32,
7879
pub right: f32,

0 commit comments

Comments
 (0)