diff --git a/crates/bevy_ecs/src/reflect/resource.rs b/crates/bevy_ecs/src/reflect/resource.rs index 238fd5f4e77ae..34e593a6ef00e 100644 --- a/crates/bevy_ecs/src/reflect/resource.rs +++ b/crates/bevy_ecs/src/reflect/resource.rs @@ -8,7 +8,7 @@ use crate::{ change_detection::Mut, component::ComponentId, resource::Resource, - world::{unsafe_world_cell::UnsafeWorldCell, World}, + world::{unsafe_world_cell::UnsafeWorldCell, FilteredResources, FilteredResourcesMut, World}, }; use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry}; @@ -52,7 +52,9 @@ pub struct ReflectResourceFns { /// Function pointer implementing [`ReflectResource::remove()`]. pub remove: fn(&mut World), /// Function pointer implementing [`ReflectResource::reflect()`]. - pub reflect: fn(&World) -> Option<&dyn Reflect>, + pub reflect: for<'w> fn(FilteredResources<'w, '_>) -> Option<&'w dyn Reflect>, + /// Function pointer implementing [`ReflectResource::reflect_mut()`]. + pub reflect_mut: for<'w> fn(FilteredResourcesMut<'w, '_>) -> Option>, /// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`]. /// /// # Safety @@ -111,14 +113,23 @@ impl ReflectResource { } /// Gets the value of this [`Resource`] type from the world as a reflected reference. - pub fn reflect<'a>(&self, world: &'a World) -> Option<&'a dyn Reflect> { - (self.0.reflect)(world) + /// + /// Note that [`&World`](World) is a valid type for `resources`. + pub fn reflect<'w, 's>( + &self, + resources: impl Into>, + ) -> Option<&'w dyn Reflect> { + (self.0.reflect)(resources.into()) } /// Gets the value of this [`Resource`] type from the world as a mutable reflected reference. - pub fn reflect_mut<'a>(&self, world: &'a mut World) -> Option> { - // SAFETY: unique world access - unsafe { (self.0.reflect_unchecked_mut)(world.as_unsafe_world_cell()) } + /// + /// Note that [`&mut World`](World) is a valid type for `resources`. + pub fn reflect_mut<'w, 's>( + &self, + resources: impl Into>, + ) -> Option> { + (self.0.reflect_mut)(resources.into()) } /// # Safety @@ -212,7 +223,12 @@ impl FromType for ReflectResource { remove: |world| { world.remove_resource::(); }, - reflect: |world| world.get_resource::().map(|res| res as &dyn Reflect), + reflect: |world| world.get::().map(|res| res.into_inner() as &dyn Reflect), + reflect_mut: |world| { + world + .into_mut::() + .map(|res| res.map_unchanged(|value| value as &mut dyn Reflect)) + }, reflect_unchecked_mut: |world| { // SAFETY: all usages of `reflect_unchecked_mut` guarantee that there is either a single mutable // reference or multiple immutable ones alive at any given point diff --git a/crates/bevy_ecs/src/system/builder.rs b/crates/bevy_ecs/src/system/builder.rs index a5556f123b516..6261b9e35587e 100644 --- a/crates/bevy_ecs/src/system/builder.rs +++ b/crates/bevy_ecs/src/system/builder.rs @@ -715,9 +715,11 @@ mod tests { use crate::{ entity::Entities, prelude::{Component, Query}, + reflect::ReflectResource, system::{Local, RunSystemOnce}, }; use alloc::vec; + use bevy_reflect::{FromType, Reflect, ReflectRef}; use super::*; @@ -730,8 +732,11 @@ mod tests { #[derive(Component)] struct C; - #[derive(Resource, Default)] - struct R; + #[derive(Resource, Default, Reflect)] + #[reflect(Resource)] + struct R { + foo: usize, + } fn local_system(local: Local) -> u64 { *local @@ -1071,4 +1076,31 @@ mod tests { .build_state(&mut world) .build_system(|_r: ResMut, _fr: FilteredResourcesMut| {}); } + + #[test] + fn filtered_resource_reflect() { + let mut world = World::new(); + world.insert_resource(R { foo: 7 }); + + let system = (FilteredResourcesParamBuilder::new(|builder| { + builder.add_read::(); + }),) + .build_state(&mut world) + .build_system(|res: FilteredResources| { + let reflect_resource = >::from_type(); + let ReflectRef::Struct(reflect_struct) = + reflect_resource.reflect(res).unwrap().reflect_ref() + else { + panic!() + }; + *reflect_struct + .field("foo") + .unwrap() + .try_downcast_ref::() + .unwrap() + }); + + let output = world.run_system_once(system).unwrap(); + assert_eq!(output, 7); + } }