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 1 commit
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
85 changes: 85 additions & 0 deletions crates/bevy_ecs/src/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub use crate::change_detection::ReflectMut;
use crate::{
component::Component,
entity::{Entity, EntityMap, MapEntities, MapEntitiesError},
system::Resource,
world::{FromWorld, World},
};
use bevy_reflect::{
Expand Down Expand Up @@ -123,6 +124,90 @@ impl<C: Component + Reflect + FromWorld> FromType<C> for ReflectComponent {
}
}

#[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 {
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);
}

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);
}

pub fn remove_resource(&self, world: &mut World) {
Shatur marked this conversation as resolved.
Show resolved Hide resolved
(self.remove_resource)(world);
}

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)
}

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)
}

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.get_resource_mut::<C>().unwrap();
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.get_resource::<C>().unwrap();
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