Skip to content

Commit f867319

Browse files
add ReflectAsset and ReflectHandle (#5923)
# Objective ![image](https://user-images.githubusercontent.com/22177966/189350194-639a0211-e984-4f73-ae62-0ede44891eb9.png) ^ enable this Concretely, I need to - list all handle ids for an asset type - fetch the asset as `dyn Reflect`, given a `HandleUntyped` - when encountering a `Handle<T>`, find out what asset type that handle refers to (`T`'s type id) and turn the handle into a `HandleUntyped` ## Solution - add `ReflectAsset` type containing function pointers for working with assets ```rust pub struct ReflectAsset { type_uuid: Uuid, assets_resource_type_id: TypeId, // TypeId of the `Assets<T>` resource get: fn(&World, HandleUntyped) -> Option<&dyn Reflect>, get_mut: fn(&mut World, HandleUntyped) -> Option<&mut dyn Reflect>, get_unchecked_mut: unsafe fn(&World, HandleUntyped) -> Option<&mut dyn Reflect>, add: fn(&mut World, &dyn Reflect) -> HandleUntyped, set: fn(&mut World, HandleUntyped, &dyn Reflect) -> HandleUntyped, len: fn(&World) -> usize, ids: for<'w> fn(&'w World) -> Box<dyn Iterator<Item = HandleId> + 'w>, remove: fn(&mut World, HandleUntyped) -> Option<Box<dyn Reflect>>, } ``` - add `ReflectHandle` type relating the handle back to the asset type and providing a way to create a `HandleUntyped` ```rust pub struct ReflectHandle { type_uuid: Uuid, asset_type_id: TypeId, downcast_handle_untyped: fn(&dyn Any) -> Option<HandleUntyped>, } ``` - add the corresponding `FromType` impls - add a function `app.register_asset_reflect` which is supposed to be called after `.add_asset` and registers `ReflectAsset` and `ReflectHandle` in the type registry --- ## Changelog - add `ReflectAsset` and `ReflectHandle` types, which allow code to use reflection to manipulate arbitrary assets without knowing their types at compile time
1 parent 0401f04 commit f867319

File tree

15 files changed

+395
-26
lines changed

15 files changed

+395
-26
lines changed

crates/bevy_animation/src/lib.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use bevy_ecs::{
1717
};
1818
use bevy_hierarchy::Children;
1919
use bevy_math::{Quat, Vec3};
20-
use bevy_reflect::{Reflect, TypeUuid};
20+
use bevy_reflect::{FromReflect, Reflect, TypeUuid};
2121
use bevy_time::Time;
2222
use bevy_transform::{prelude::Transform, TransformSystem};
2323
use bevy_utils::{tracing::warn, HashMap};
@@ -31,7 +31,7 @@ pub mod prelude {
3131
}
3232

3333
/// List of keyframes for one of the attribute of a [`Transform`].
34-
#[derive(Clone, Debug)]
34+
#[derive(Reflect, FromReflect, Clone, Debug)]
3535
pub enum Keyframes {
3636
/// Keyframes for rotation.
3737
Rotation(Vec<Quat>),
@@ -44,7 +44,7 @@ pub enum Keyframes {
4444
/// Describes how an attribute of a [`Transform`] should be animated.
4545
///
4646
/// `keyframe_timestamps` and `keyframes` should have the same length.
47-
#[derive(Clone, Debug)]
47+
#[derive(Reflect, FromReflect, Clone, Debug)]
4848
pub struct VariableCurve {
4949
/// Timestamp for each of the keyframes.
5050
pub keyframe_timestamps: Vec<f32>,
@@ -53,14 +53,14 @@ pub struct VariableCurve {
5353
}
5454

5555
/// Path to an entity, with [`Name`]s. Each entity in a path must have a name.
56-
#[derive(Clone, Debug, Hash, PartialEq, Eq, Default)]
56+
#[derive(Reflect, FromReflect, Clone, Debug, Hash, PartialEq, Eq, Default)]
5757
pub struct EntityPath {
5858
/// Parts of the path
5959
pub parts: Vec<Name>,
6060
}
6161

6262
/// A list of [`VariableCurve`], and the [`EntityPath`] to which they apply.
63-
#[derive(Clone, TypeUuid, Debug, Default)]
63+
#[derive(Reflect, FromReflect, Clone, TypeUuid, Debug, Default)]
6464
#[uuid = "d81b7179-0448-4eb0-89fe-c067222725bf"]
6565
pub struct AnimationClip {
6666
curves: HashMap<EntityPath, Vec<VariableCurve>>,
@@ -301,6 +301,7 @@ pub struct AnimationPlugin {}
301301
impl Plugin for AnimationPlugin {
302302
fn build(&self, app: &mut App) {
303303
app.add_asset::<AnimationClip>()
304+
.register_asset_reflect::<AnimationClip>()
304305
.register_type::<AnimationPlayer>()
305306
.add_system_to_stage(
306307
CoreStage::PostUpdate,

crates/bevy_app/src/app.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::{CoreStage, Plugin, PluginGroup, StartupSchedule, StartupStage};
22
pub use bevy_derive::AppLabel;
3-
use bevy_derive::{Deref, DerefMut};
43
use bevy_ecs::{
54
event::{Event, Events},
65
prelude::FromWorld,
@@ -25,7 +24,7 @@ bevy_utils::define_label!(
2524

2625
/// The [`Resource`] that stores the [`App`]'s [`TypeRegistry`](bevy_reflect::TypeRegistry).
2726
#[cfg(feature = "bevy_reflect")]
28-
#[derive(Resource, Clone, Deref, DerefMut, Default)]
27+
#[derive(Resource, Clone, bevy_derive::Deref, bevy_derive::DerefMut, Default)]
2928
pub struct AppTypeRegistry(pub bevy_reflect::TypeRegistryArc);
3029

3130
#[allow(clippy::needless_doctest_main)]

crates/bevy_asset/src/assets.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use crate::{
22
update_asset_storage_system, Asset, AssetLoader, AssetServer, AssetStage, Handle, HandleId,
3-
RefChange,
3+
RefChange, ReflectAsset, ReflectHandle,
44
};
5-
use bevy_app::App;
5+
use bevy_app::{App, AppTypeRegistry};
66
use bevy_ecs::{
77
event::{EventWriter, Events},
88
system::{ResMut, Resource},
99
world::FromWorld,
1010
};
11+
use bevy_reflect::{FromReflect, GetTypeRegistration, Reflect};
1112
use bevy_utils::HashMap;
1213
use crossbeam_channel::Sender;
1314
use std::fmt::Debug;
@@ -279,6 +280,14 @@ pub trait AddAsset {
279280
where
280281
T: Asset;
281282

283+
/// Registers the asset type `T` using `[App::register]`,
284+
/// and adds [`ReflectAsset`] type data to `T` and [`ReflectHandle`] type data to [`Handle<T>`] in the type registry.
285+
///
286+
/// This enables reflection code to access assets. For detailed information, see the docs on [`ReflectAsset`] and [`ReflectHandle`].
287+
fn register_asset_reflect<T>(&mut self) -> &mut Self
288+
where
289+
T: Asset + Reflect + FromReflect + GetTypeRegistration;
290+
282291
/// Registers `T` as a supported internal asset in the application.
283292
///
284293
/// Internal assets (e.g. shaders) are bundled directly into the app and can't be hot reloaded
@@ -332,6 +341,23 @@ impl AddAsset for App {
332341
.add_event::<AssetEvent<T>>()
333342
}
334343

344+
fn register_asset_reflect<T>(&mut self) -> &mut Self
345+
where
346+
T: Asset + Reflect + FromReflect + GetTypeRegistration,
347+
{
348+
let type_registry = self.world.resource::<AppTypeRegistry>();
349+
{
350+
let mut type_registry = type_registry.write();
351+
352+
type_registry.register::<T>();
353+
type_registry.register::<Handle<T>>();
354+
type_registry.register_type_data::<T, ReflectAsset>();
355+
type_registry.register_type_data::<Handle<T>, ReflectHandle>();
356+
}
357+
358+
self
359+
}
360+
335361
fn add_debug_asset<T: Clone>(&mut self) -> &mut Self
336362
where
337363
T: Asset,

crates/bevy_asset/src/handle.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,16 @@ impl Drop for HandleUntyped {
410410
}
411411
}
412412

413+
impl<A: Asset> From<Handle<A>> for HandleUntyped {
414+
fn from(mut handle: Handle<A>) -> Self {
415+
let handle_type = std::mem::replace(&mut handle.handle_type, HandleType::Weak);
416+
HandleUntyped {
417+
id: handle.id,
418+
handle_type,
419+
}
420+
}
421+
}
422+
413423
impl From<&HandleUntyped> for HandleId {
414424
fn from(value: &HandleUntyped) -> Self {
415425
value.id

crates/bevy_asset/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ mod info;
2525
mod io;
2626
mod loader;
2727
mod path;
28+
mod reflect;
2829

2930
/// The `bevy_asset` prelude.
3031
pub mod prelude {
@@ -43,6 +44,7 @@ pub use info::*;
4344
pub use io::*;
4445
pub use loader::*;
4546
pub use path::*;
47+
pub use reflect::*;
4648

4749
use bevy_app::{prelude::Plugin, App};
4850
use bevy_ecs::schedule::{StageLabel, SystemStage};

0 commit comments

Comments
 (0)