Support using FilteredResources with ReflectResource. (#15624)
# Objective Support accessing resources using reflection when using `FilteredResources` in a dynamic system. This is similar to how components can be queried using reflection when using `FilteredEntityRef|Mut`. ## Solution Change `ReflectResource` from taking `&World` and `&mut World` to taking `impl Into<FilteredResources>` and `impl Into<FilteredResourcesMut>`, similar to how `ReflectComponent` takes `impl Into<FilteredEntityRef>` and `impl Into<FilteredEntityMut>`. There are `From` impls that ensure code passing `&World` and `&mut World` continues to work as before. ## Migration Guide If you are manually creating a `ReflectComponentFns` struct, the `reflect` function now takes `FilteredResources` instead `&World`, and there is a new `reflect_mut` function that takes `FilteredResourcesMut`.
This commit is contained in:
parent
d7fd00a8b9
commit
0a32450715
@ -8,7 +8,7 @@ use crate::{
|
|||||||
change_detection::Mut,
|
change_detection::Mut,
|
||||||
component::ComponentId,
|
component::ComponentId,
|
||||||
resource::Resource,
|
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};
|
use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
|
||||||
|
|
||||||
@ -52,7 +52,9 @@ pub struct ReflectResourceFns {
|
|||||||
/// Function pointer implementing [`ReflectResource::remove()`].
|
/// Function pointer implementing [`ReflectResource::remove()`].
|
||||||
pub remove: fn(&mut World),
|
pub remove: fn(&mut World),
|
||||||
/// Function pointer implementing [`ReflectResource::reflect()`].
|
/// 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<Mut<'w, dyn Reflect>>,
|
||||||
/// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`].
|
/// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`].
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -111,14 +113,23 @@ impl ReflectResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the value of this [`Resource`] type from the world as a reflected reference.
|
/// 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<FilteredResources<'w, 's>>,
|
||||||
|
) -> Option<&'w dyn Reflect> {
|
||||||
|
(self.0.reflect)(resources.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the value of this [`Resource`] type from the world as a mutable reflected reference.
|
/// 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<Mut<'a, dyn Reflect>> {
|
///
|
||||||
// SAFETY: unique world access
|
/// Note that [`&mut World`](World) is a valid type for `resources`.
|
||||||
unsafe { (self.0.reflect_unchecked_mut)(world.as_unsafe_world_cell()) }
|
pub fn reflect_mut<'w, 's>(
|
||||||
|
&self,
|
||||||
|
resources: impl Into<FilteredResourcesMut<'w, 's>>,
|
||||||
|
) -> Option<Mut<'w, dyn Reflect>> {
|
||||||
|
(self.0.reflect_mut)(resources.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -212,7 +223,12 @@ impl<R: Resource + FromReflect + TypePath> FromType<R> for ReflectResource {
|
|||||||
remove: |world| {
|
remove: |world| {
|
||||||
world.remove_resource::<R>();
|
world.remove_resource::<R>();
|
||||||
},
|
},
|
||||||
reflect: |world| world.get_resource::<R>().map(|res| res as &dyn Reflect),
|
reflect: |world| world.get::<R>().map(|res| res.into_inner() as &dyn Reflect),
|
||||||
|
reflect_mut: |world| {
|
||||||
|
world
|
||||||
|
.into_mut::<R>()
|
||||||
|
.map(|res| res.map_unchanged(|value| value as &mut dyn Reflect))
|
||||||
|
},
|
||||||
reflect_unchecked_mut: |world| {
|
reflect_unchecked_mut: |world| {
|
||||||
// SAFETY: all usages of `reflect_unchecked_mut` guarantee that there is either a single mutable
|
// 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
|
// reference or multiple immutable ones alive at any given point
|
||||||
|
@ -715,9 +715,11 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
entity::Entities,
|
entity::Entities,
|
||||||
prelude::{Component, Query},
|
prelude::{Component, Query},
|
||||||
|
reflect::ReflectResource,
|
||||||
system::{Local, RunSystemOnce},
|
system::{Local, RunSystemOnce},
|
||||||
};
|
};
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
|
use bevy_reflect::{FromType, Reflect, ReflectRef};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -730,8 +732,11 @@ mod tests {
|
|||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct C;
|
struct C;
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default, Reflect)]
|
||||||
struct R;
|
#[reflect(Resource)]
|
||||||
|
struct R {
|
||||||
|
foo: usize,
|
||||||
|
}
|
||||||
|
|
||||||
fn local_system(local: Local<u64>) -> u64 {
|
fn local_system(local: Local<u64>) -> u64 {
|
||||||
*local
|
*local
|
||||||
@ -1071,4 +1076,31 @@ mod tests {
|
|||||||
.build_state(&mut world)
|
.build_state(&mut world)
|
||||||
.build_system(|_r: ResMut<R>, _fr: FilteredResourcesMut| {});
|
.build_system(|_r: ResMut<R>, _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::<R>();
|
||||||
|
}),)
|
||||||
|
.build_state(&mut world)
|
||||||
|
.build_system(|res: FilteredResources| {
|
||||||
|
let reflect_resource = <ReflectResource as FromType<R>>::from_type();
|
||||||
|
let ReflectRef::Struct(reflect_struct) =
|
||||||
|
reflect_resource.reflect(res).unwrap().reflect_ref()
|
||||||
|
else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
*reflect_struct
|
||||||
|
.field("foo")
|
||||||
|
.unwrap()
|
||||||
|
.try_downcast_ref::<usize>()
|
||||||
|
.unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = world.run_system_once(system).unwrap();
|
||||||
|
assert_eq!(output, 7);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user