Skip to content

Commit

Permalink
Allow registering of resources via ReflectResource / ReflectComponent (
Browse files Browse the repository at this point in the history
…#15496)

# Objective

- Resolves #15453
## Solution

- Added new `World::resource_id` and `World::register_resource` methods
to support this feature
- Added new `ReflectResource::register_resource` method, and new pointer
to this new function
- Added new `ReflectComponent::register_component`

## Testing

- Tested this locally, but couldn't test the entire crate locally, just
this new feature, expect that CI will do the rest of the work.

---

## Showcase


```rs
#[derive(Component, Reflect)]
#[reflect(Component)]
struct MyComp;

let mut world = World::new();
let mut registry = TypeRegistration::of::<MyComp>();
registry.insert::<ReflectComponent>(FromType::<MyComp>::from_type());
let data = registry.data::<ReflectComponent>().unwrap();

// Its now possible to register the Component in the world this way
let component_id = data.register_component(&mut world);

// They will be the same
assert_eq!(component_id, world.component_id::<MyComp>().unwrap());
```

```rs
#[derive(Resource, Reflect)]
#[reflect(Resource)]
struct MyResource;

let mut world = World::new();
let mut registry = TypeRegistration::of::<MyResource>();
registry.insert::<ReflectResource>(FromType::<MyResource>::from_type());
let data = registry.data::<ReflectResource>().unwrap();

// Same with resources
let component_id = data.register_resource(&mut world);

// They match
assert_eq!(component_id, world.resource_id::<MyResource>().unwrap());
```
  • Loading branch information
pablo-lua authored Sep 28, 2024
1 parent c148665 commit c32e0b9
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 1 deletion.
12 changes: 11 additions & 1 deletion crates/bevy_ecs/src/reflect/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
use super::from_reflect_with_fallback;
use crate::{
change_detection::Mut,
component::Component,
component::{Component, ComponentId},
entity::Entity,
world::{
unsafe_world_cell::UnsafeEntityCell, EntityMut, EntityWorldMut, FilteredEntityMut,
Expand Down Expand Up @@ -119,6 +119,8 @@ pub struct ReflectComponentFns {
pub reflect_unchecked_mut: unsafe fn(UnsafeEntityCell<'_>) -> Option<Mut<'_, dyn Reflect>>,
/// Function pointer implementing [`ReflectComponent::copy()`].
pub copy: fn(&World, &mut World, Entity, Entity, &TypeRegistry),
/// Function pointer implementing [`ReflectComponent::register_component()`].
pub register_component: fn(&mut World) -> ComponentId,
}

impl ReflectComponentFns {
Expand Down Expand Up @@ -220,6 +222,11 @@ impl ReflectComponent {
);
}

/// Register the type of this [`Component`] in [`World`], returning its [`ComponentId`].
pub fn register_component(&self, world: &mut World) -> ComponentId {
(self.0.register_component)(world)
}

/// Create a custom implementation of [`ReflectComponent`].
///
/// This is an advanced feature,
Expand Down Expand Up @@ -303,6 +310,9 @@ impl<C: Component + Reflect + TypePath> FromType<C> for ReflectComponent {
let c = unsafe { entity.get_mut::<C>() };
c.map(|c| c.map_unchanged(|value| value as &mut dyn Reflect))
},
register_component: |world: &mut World| -> ComponentId {
world.register_component::<C>()
},
})
}
}
12 changes: 12 additions & 0 deletions crates/bevy_ecs/src/reflect/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use crate::{
change_detection::Mut,
component::ComponentId,
system::Resource,
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
Expand Down Expand Up @@ -59,6 +60,8 @@ pub struct ReflectResourceFns {
pub reflect_unchecked_mut: unsafe fn(UnsafeWorldCell<'_>) -> Option<Mut<'_, dyn Reflect>>,
/// Function pointer implementing [`ReflectResource::copy()`].
pub copy: fn(&World, &mut World, &TypeRegistry),
/// Function pointer implementing [`ReflectResource::register_resource()`].
pub register_resource: fn(&mut World) -> ComponentId,
}

impl ReflectResourceFns {
Expand Down Expand Up @@ -145,6 +148,11 @@ impl ReflectResource {
(self.0.copy)(source_world, destination_world, registry);
}

/// Register the type of this [`Resource`] in [`World`], returning the [`ComponentId`]
pub fn register_resource(&self, world: &mut World) -> ComponentId {
(self.0.register_resource)(world)
}

/// Create a custom implementation of [`ReflectResource`].
///
/// This is an advanced feature,
Expand Down Expand Up @@ -217,6 +225,10 @@ impl<R: Resource + FromReflect + TypePath> FromType<R> for ReflectResource {
from_reflect_with_fallback::<R>(source_resource, destination_world, registry);
destination_world.insert_resource(destination_resource);
},

register_resource: |world: &mut World| -> ComponentId {
world.register_resource::<R>()
},
})
}
}
19 changes: 19 additions & 0 deletions crates/bevy_ecs/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,25 @@ impl World {
self.components.component_id::<T>()
}

/// Registers a new [`Resource`] type and returns the [`ComponentId`] created for it.
///
/// Note that the resource doesn't have a value in world, it's only registered.
/// if you want to insert the [`Resource`] in the [`World`], use [`World::init_resource`] or [`World::insert_resource`] instead.
pub fn register_resource<R: Resource>(&mut self) -> ComponentId {
self.components.register_resource::<R>()
}

/// Returns the [`ComponentId`] of the given [`Resource`] type `T`.
///
/// The returned `ComponentId` is specific to the `World` instance
/// it was retrieved from and should not be used with another `World` instance.
///
/// Returns [`None`] if the `Resource` type has not yet been initialized within
/// the `World` using [`World::register_resource`], [`World::init_resource`] or [`World::insert_resource`].
pub fn resource_id<T: Resource>(&self) -> Option<ComponentId> {
self.components.get_resource_id(TypeId::of::<T>())
}

/// Retrieves an [`EntityRef`] that exposes read-only operations for the given `entity`.
/// This will panic if the `entity` does not exist. Use [`World::get_entity`] if you want
/// to check for entity existence instead of implicitly panic-ing.
Expand Down

0 comments on commit c32e0b9

Please sign in to comment.