Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Add reflection for resources #5175

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/bevy_core_pipeline/src/clear_color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ pub enum ClearColorConfig {
///
/// This color appears as the "background" color for simple apps, when
/// there are portions of the screen with nothing rendered.
#[derive(Component, Clone, Debug, Deref, DerefMut, ExtractResource)]
#[derive(Component, Clone, Debug, Deref, DerefMut, ExtractResource, Reflect)]
#[reflect(Resource)]
pub struct ClearColor(pub Color);

impl Default for ClearColor {
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ pub struct CorePipelinePlugin;

impl Plugin for CorePipelinePlugin {
fn build(&self, app: &mut App) {
app.init_resource::<ClearColor>()
app.register_type::<ClearColor>()
.init_resource::<ClearColor>()
.add_plugin(ExtractResourcePlugin::<ClearColor>::default())
.add_plugin(Core2dPlugin)
.add_plugin(Core3dPlugin);
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/change_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ change_detection_impl!(Mut<'a, T>, T,);
impl_into_inner!(Mut<'a, T>, T,);
impl_debug!(Mut<'a, T>,);

/// Unique mutable borrow of a Reflected component
/// Unique mutable borrow of a reflected component or resource
#[cfg(feature = "bevy_reflect")]
pub struct ReflectMut<'a> {
pub(crate) value: &'a mut dyn Reflect,
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use bevy_ptr as ptr;
pub mod prelude {
#[doc(hidden)]
#[cfg(feature = "bevy_reflect")]
pub use crate::reflect::ReflectComponent;
pub use crate::reflect::{ReflectComponent, ReflectResource};
#[doc(hidden)]
pub use crate::{
bundle::Bundle,
Expand Down
131 changes: 130 additions & 1 deletion crates/bevy_ecs/src/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ pub use crate::change_detection::ReflectMut;
use crate::{
component::Component,
entity::{Entity, EntityMap, MapEntities, MapEntitiesError},
system::Resource,
world::{FromWorld, World},
};
use bevy_reflect::{
impl_from_reflect_value, impl_reflect_value, FromType, Reflect, ReflectDeserialize,
ReflectSerialize,
};

/// A struct used to operate on reflected [`Component`] of a type.
///
/// A [`ReflectComponent`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectComponent {
add_component: fn(&mut World, Entity, &dyn Reflect),
Expand All @@ -22,18 +27,34 @@ pub struct ReflectComponent {
}

impl ReflectComponent {
/// Insert a reflected [`Component`] into the entity like [`insert()`](crate::world::EntityMut::insert).
///
/// # Panics
///
/// Panics if there is no such entity.
pub fn add_component(&self, world: &mut World, entity: Entity, component: &dyn Reflect) {
(self.add_component)(world, entity, component);
}

/// Uses reflection to set the value of this [`Component`] type in the entity to the given value.
///
/// # Panics
///
/// Panics if there is no [`Component`] of the given type or such entity.
Shatur marked this conversation as resolved.
Show resolved Hide resolved
pub fn apply_component(&self, world: &mut World, entity: Entity, component: &dyn Reflect) {
(self.apply_component)(world, entity, component);
}

/// Removes this [`Component`] type from the entity. Does nothing if it doesn't exist.
///
/// # Panics
///
/// Panics if there is no such entity
Shatur marked this conversation as resolved.
Show resolved Hide resolved
pub fn remove_component(&self, world: &mut World, entity: Entity) {
(self.remove_component)(world, entity);
}

/// Gets the value of this [`Component`] type from the entity as a reflected reference.
pub fn reflect_component<'a>(
&self,
world: &'a World,
Expand All @@ -42,6 +63,7 @@ impl ReflectComponent {
(self.reflect_component)(world, entity)
}

/// Gets the value of this [`Component`] type from the entity as a mutable reflected reference.
pub fn reflect_component_mut<'a>(
&self,
world: &'a mut World,
Expand All @@ -56,7 +78,7 @@ impl ReflectComponent {
/// violating Rust's aliasing rules. To avoid this:
/// * Only call this method in an exclusive system to avoid sharing across threads (or use a
/// scheduler that enforces safe memory access).
/// * Don't call this method more than once in the same scope for a given component.
/// * Don't call this method more than once in the same scope for a given [`Component`].
pub unsafe fn reflect_component_unchecked_mut<'a>(
&self,
world: &'a World,
Expand All @@ -65,6 +87,11 @@ impl ReflectComponent {
(self.reflect_component_mut)(world, entity)
}

/// Gets the value of this [`Component`] type from entity from `source_world` and [applies](Self::apply_component()) it to the value of this [`Component`] type in entity in `destination_world`.
///
/// # Panics
///
/// Panics if there is no [`Component`] of the given type or such entities.
Shatur marked this conversation as resolved.
Show resolved Hide resolved
pub fn copy_component(
&self,
source_world: &World,
Expand Down Expand Up @@ -123,6 +150,108 @@ impl<C: Component + Reflect + FromWorld> FromType<C> for ReflectComponent {
}
}

/// A struct used to operate on reflected [`Resource`] of a type.
///
/// A [`ReflectResource`] for type `T` can be obtained via
/// [`bevy_reflect::TypeRegistration::data`].
#[derive(Clone)]
pub struct ReflectResource {
Shatur marked this conversation as resolved.
Show resolved Hide resolved
insert_resource: fn(&mut World, &dyn Reflect),
apply_resource: fn(&mut World, &dyn Reflect),
remove_resource: fn(&mut World),
reflect_resource: fn(&World) -> Option<&dyn Reflect>,
reflect_resource_unchecked_mut: unsafe fn(&World) -> Option<ReflectMut>,
copy_resource: fn(&World, &mut World),
}

impl ReflectResource {
/// Insert a reflected [`Resource`] into the world like [`insert_resource()`](World::insert_resource).
pub fn insert_resource(&self, world: &mut World, resource: &dyn Reflect) {
Shatur marked this conversation as resolved.
Show resolved Hide resolved
(self.insert_resource)(world, resource);
}

/// Uses reflection to set the value of this [`Resource`] type in the world to the given value.
///
/// # Panics
///
/// Panics if there is no [`Resource`] of the given type.
pub fn apply_resource(&self, world: &mut World, resource: &dyn Reflect) {
Shatur marked this conversation as resolved.
Show resolved Hide resolved
(self.apply_resource)(world, resource);
}

/// Removes this [`Resource`] type from the world. Does nothing if it doesn't exist.
pub fn remove_resource(&self, world: &mut World) {
Shatur marked this conversation as resolved.
Show resolved Hide resolved
(self.remove_resource)(world);
}

/// Gets the value of this [`Resource`] type from the world as a reflected reference.
pub fn reflect_resource<'a>(&self, world: &'a World) -> Option<&'a dyn Reflect> {
Shatur marked this conversation as resolved.
Show resolved Hide resolved
(self.reflect_resource)(world)
}

/// Gets the value of this [`Resource`] type from the world as a mutable reflected reference.
pub fn reflect_resource_mut<'a>(&self, world: &'a mut World) -> Option<ReflectMut<'a>> {
Shatur marked this conversation as resolved.
Show resolved Hide resolved
// SAFE: unique world access
unsafe { (self.reflect_resource_unchecked_mut)(world) }
}

/// # Safety
/// This method does not prevent you from having two mutable pointers to the same data,
/// violating Rust's aliasing rules. To avoid this:
/// * Only call this method in an exclusive system to avoid sharing across threads (or use a
/// scheduler that enforces safe memory access).
/// * Don't call this method more than once in the same scope for a given [`Resource`].
pub unsafe fn reflect_resource_unckecked_mut<'a>(
&self,
world: &'a World,
) -> Option<ReflectMut<'a>> {
(self.reflect_resource_unchecked_mut)(world)
}

/// Gets the value of this [`Resource`] type from `source_world` and [applies](Self::apply_resource()) it to the value of this [`Resource`] type in `destination_world`.
///
/// # Panics
///
/// Panics if there is no [`Resource`] of the given type.
pub fn copy_resource(&self, source_world: &World, destination_world: &mut World) {
Shatur marked this conversation as resolved.
Show resolved Hide resolved
(self.copy_resource)(source_world, destination_world);
}
}

impl<C: Resource + Reflect + FromWorld> FromType<C> for ReflectResource {
fn from_type() -> Self {
ReflectResource {
insert_resource: |world, reflected_resource| {
let mut resource = C::from_world(world);
resource.apply(reflected_resource);
world.insert_resource(resource);
},
apply_resource: |world, reflected_resource| {
let mut resource = world.resource_mut::<C>();
resource.apply(reflected_resource);
},
remove_resource: |world| {
world.remove_resource::<C>();
},
reflect_resource: |world| world.get_resource::<C>().map(|res| res as &dyn Reflect),
reflect_resource_unchecked_mut: |world| unsafe {
world
.get_resource_unchecked_mut::<C>()
.map(|res| ReflectMut {
value: res.value as &mut dyn Reflect,
ticks: res.ticks,
})
},
copy_resource: |source_world, destination_world| {
let source_resource = source_world.resource::<C>();
let mut destination_resource = C::from_world(destination_world);
destination_resource.apply(source_resource);
destination_world.insert_resource(destination_resource);
},
}
}
}

impl_reflect_value!(Entity(Hash, PartialEq, Serialize, Deserialize));
impl_from_reflect_value!(Entity);

Expand Down
3 changes: 3 additions & 0 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ impl Plugin for PbrPlugin {
.register_type::<PointLight>()
.add_plugin(MeshRenderPlugin)
.add_plugin(MaterialPlugin::<StandardMaterial>::default())
.register_type::<AmbientLight>()
.register_type::<DirectionalLightShadowMap>()
.register_type::<PointLightShadowMap>()
.init_resource::<AmbientLight>()
.init_resource::<GlobalVisiblePointLights>()
.init_resource::<DirectionalLightShadowMap>()
Expand Down
9 changes: 6 additions & 3 deletions crates/bevy_pbr/src/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ impl PointLight {
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.6;
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, Reflect)]
#[reflect(Resource)]
pub struct PointLightShadowMap {
pub size: usize,
}
Expand Down Expand Up @@ -153,7 +154,8 @@ impl DirectionalLight {
pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 0.6;
}

#[derive(Clone, Debug)]
#[derive(Clone, Debug, Reflect)]
#[reflect(Resource)]
pub struct DirectionalLightShadowMap {
pub size: usize,
}
Expand All @@ -168,7 +170,8 @@ impl Default for DirectionalLightShadowMap {
}

/// An ambient light, which lights the entire scene equally.
#[derive(Clone, Debug, ExtractResource)]
#[derive(Clone, Debug, ExtractResource, Reflect)]
#[reflect(Resource)]
pub struct AmbientLight {
pub color: Color,
/// A direct scale factor multiplied with `color` before being passed to the shader.
Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_pbr/src/wireframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ impl Plugin for WireframePlugin {
Shader::from_wgsl
);

app.init_resource::<WireframeConfig>()
app.register_type::<WireframeConfig>()
.init_resource::<WireframeConfig>()
.add_plugin(ExtractResourcePlugin::<WireframeConfig>::default());

if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
Expand All @@ -60,7 +61,8 @@ fn extract_wireframes(mut commands: Commands, query: Query<Entity, With<Wirefram
#[reflect(Component, Default)]
pub struct Wireframe;

#[derive(Debug, Clone, Default, ExtractResource)]
#[derive(Debug, Clone, Default, ExtractResource, Reflect)]
#[reflect(Resource)]
pub struct WireframeConfig {
/// Whether to show wireframes for all meshes. If `false`, only meshes with a [Wireframe] component will be rendered.
pub global: bool,
Expand Down
7 changes: 5 additions & 2 deletions crates/bevy_render/src/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ use crate::{
use bevy_app::{App, Plugin};
use bevy_ecs::prelude::*;
use bevy_math::{Mat4, Vec3};
use bevy_reflect::Reflect;
use bevy_transform::components::GlobalTransform;
use bevy_utils::HashMap;

pub struct ViewPlugin;

impl Plugin for ViewPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<Msaa>()
app.register_type::<Msaa>()
.init_resource::<Msaa>()
// NOTE: windows.is_changed() handles cases where a window was resized
.add_plugin(ExtractResourcePlugin::<Msaa>::default())
.add_plugin(VisibilityPlugin);
Expand All @@ -45,7 +47,6 @@ impl Plugin for ViewPlugin {
}
}

#[derive(Clone, ExtractResource)]
/// Configuration resource for [Multi-Sample Anti-Aliasing](https://en.wikipedia.org/wiki/Multisample_anti-aliasing).
///
/// # Example
Expand All @@ -56,6 +57,8 @@ impl Plugin for ViewPlugin {
/// .insert_resource(Msaa { samples: 4 })
/// .run();
/// ```
#[derive(Clone, ExtractResource, Reflect)]
#[reflect(Resource)]
pub struct Msaa {
/// The number of samples to run for Multi-Sample Anti-Aliasing. Higher numbers result in
/// smoother edges.
Expand Down