mirror of
https://github.com/bevyengine/bevy
synced 2024-11-13 00:17:27 +00:00
Add register_resource_with_descriptor
(#15501)
# Objective - Fixes #15448. ## Solution - Add `World::register_resource_with_descriptor` and `Components::register_resource_with_descriptor`. ## Testing - Added a test `dynamic_resource`.
This commit is contained in:
parent
fc93e13c36
commit
0d2eb3df88
2 changed files with 84 additions and 7 deletions
|
@ -836,7 +836,7 @@ pub struct Components {
|
|||
}
|
||||
|
||||
impl Components {
|
||||
/// Registers a component of type `T` with this instance.
|
||||
/// Registers a [`Component`] of type `T` with this instance.
|
||||
/// If a component of this type has already been registered, this will return
|
||||
/// the ID of the pre-existing component.
|
||||
///
|
||||
|
@ -876,9 +876,9 @@ impl Components {
|
|||
|
||||
/// Registers a component described by `descriptor`.
|
||||
///
|
||||
/// ## Note
|
||||
/// # Note
|
||||
///
|
||||
/// If this method is called multiple times with identical descriptors, a distinct `ComponentId`
|
||||
/// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`]
|
||||
/// will be created for each one.
|
||||
///
|
||||
/// # See also
|
||||
|
@ -1034,6 +1034,7 @@ impl Components {
|
|||
/// # See also
|
||||
///
|
||||
/// * [`Components::resource_id()`]
|
||||
/// * [`Components::register_resource_with_descriptor()`]
|
||||
#[inline]
|
||||
pub fn register_resource<T: Resource>(&mut self) -> ComponentId {
|
||||
// SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`]
|
||||
|
@ -1044,6 +1045,24 @@ impl Components {
|
|||
}
|
||||
}
|
||||
|
||||
/// Registers a [`Resource`] described by `descriptor`.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`]
|
||||
/// will be created for each one.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// * [`Components::resource_id()`]
|
||||
/// * [`Components::register_resource()`]
|
||||
pub fn register_resource_with_descriptor(
|
||||
&mut self,
|
||||
descriptor: ComponentDescriptor,
|
||||
) -> ComponentId {
|
||||
Components::register_resource_inner(&mut self.components, descriptor)
|
||||
}
|
||||
|
||||
/// Registers a [non-send resource](crate::system::NonSend) of type `T` with this instance.
|
||||
/// If a resource of this type has already been registered, this will return
|
||||
/// the ID of the pre-existing resource.
|
||||
|
@ -1069,12 +1088,20 @@ impl Components {
|
|||
let components = &mut self.components;
|
||||
*self.resource_indices.entry(type_id).or_insert_with(|| {
|
||||
let descriptor = func();
|
||||
let component_id = ComponentId(components.len());
|
||||
components.push(ComponentInfo::new(component_id, descriptor));
|
||||
component_id
|
||||
Components::register_resource_inner(components, descriptor)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn register_resource_inner(
|
||||
components: &mut Vec<ComponentInfo>,
|
||||
descriptor: ComponentDescriptor,
|
||||
) -> ComponentId {
|
||||
let component_id = ComponentId(components.len());
|
||||
components.push(ComponentInfo::new(component_id, descriptor));
|
||||
component_id
|
||||
}
|
||||
|
||||
/// Gets an iterator over all components registered with this instance.
|
||||
pub fn iter(&self) -> impl Iterator<Item = &ComponentInfo> + '_ {
|
||||
self.components.iter()
|
||||
|
|
|
@ -1320,6 +1320,23 @@ impl World {
|
|||
.map(Into::into)
|
||||
}
|
||||
|
||||
/// Registers a new [`Resource`] type and returns the [`ComponentId`] created for it.
|
||||
///
|
||||
/// This enables the dynamic registration of new [`Resource`] definitions at runtime for
|
||||
/// advanced use cases.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// Registering a [`Resource`] does not insert it into [`World`]. For insertion, you could use
|
||||
/// [`World::insert_resource_by_id`].
|
||||
pub fn register_resource_with_descriptor(
|
||||
&mut self,
|
||||
descriptor: ComponentDescriptor,
|
||||
) -> ComponentId {
|
||||
self.components
|
||||
.register_resource_with_descriptor(descriptor)
|
||||
}
|
||||
|
||||
/// Initializes a new resource and returns the [`ComponentId`] created for it.
|
||||
///
|
||||
/// If the resource already exists, nothing happens.
|
||||
|
@ -3248,6 +3265,39 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dynamic_resource() {
|
||||
let mut world = World::new();
|
||||
|
||||
let descriptor = ComponentDescriptor::new_resource::<TestResource>();
|
||||
|
||||
let component_id = world.register_resource_with_descriptor(descriptor);
|
||||
|
||||
let value = 0;
|
||||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: value is valid for the layout of `TestResource`
|
||||
unsafe {
|
||||
world.insert_resource_by_id(
|
||||
component_id,
|
||||
ptr,
|
||||
#[cfg(feature = "track_change_detection")]
|
||||
panic::Location::caller(),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// SAFETY: We know that the resource is of type `TestResource`
|
||||
let resource = unsafe {
|
||||
world
|
||||
.get_resource_by_id(component_id)
|
||||
.unwrap()
|
||||
.deref::<TestResource>()
|
||||
};
|
||||
assert_eq!(resource.0, 0);
|
||||
|
||||
assert!(world.remove_resource_by_id(component_id).is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_resource_with_layout() {
|
||||
static DROP_COUNT: AtomicU32 = AtomicU32::new(0);
|
||||
|
@ -3268,7 +3318,7 @@ mod tests {
|
|||
)
|
||||
};
|
||||
|
||||
let component_id = world.register_component_with_descriptor(descriptor);
|
||||
let component_id = world.register_resource_with_descriptor(descriptor);
|
||||
|
||||
let value: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
|
||||
OwningPtr::make(value, |ptr| {
|
||||
|
|
Loading…
Reference in a new issue