mirror of
https://github.com/bevyengine/bevy
synced 2024-11-14 00:47:32 +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 {
|
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
|
/// If a component of this type has already been registered, this will return
|
||||||
/// the ID of the pre-existing component.
|
/// the ID of the pre-existing component.
|
||||||
///
|
///
|
||||||
|
@ -876,9 +876,9 @@ impl Components {
|
||||||
|
|
||||||
/// Registers a component described by `descriptor`.
|
/// 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.
|
/// will be created for each one.
|
||||||
///
|
///
|
||||||
/// # See also
|
/// # See also
|
||||||
|
@ -1034,6 +1034,7 @@ impl Components {
|
||||||
/// # See also
|
/// # See also
|
||||||
///
|
///
|
||||||
/// * [`Components::resource_id()`]
|
/// * [`Components::resource_id()`]
|
||||||
|
/// * [`Components::register_resource_with_descriptor()`]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn register_resource<T: Resource>(&mut self) -> ComponentId {
|
pub fn register_resource<T: Resource>(&mut self) -> ComponentId {
|
||||||
// SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`]
|
// 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.
|
/// 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
|
/// If a resource of this type has already been registered, this will return
|
||||||
/// the ID of the pre-existing resource.
|
/// the ID of the pre-existing resource.
|
||||||
|
@ -1069,12 +1088,20 @@ impl Components {
|
||||||
let components = &mut self.components;
|
let components = &mut self.components;
|
||||||
*self.resource_indices.entry(type_id).or_insert_with(|| {
|
*self.resource_indices.entry(type_id).or_insert_with(|| {
|
||||||
let descriptor = func();
|
let descriptor = func();
|
||||||
let component_id = ComponentId(components.len());
|
Components::register_resource_inner(components, descriptor)
|
||||||
components.push(ComponentInfo::new(component_id, descriptor));
|
|
||||||
component_id
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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.
|
/// Gets an iterator over all components registered with this instance.
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &ComponentInfo> + '_ {
|
pub fn iter(&self) -> impl Iterator<Item = &ComponentInfo> + '_ {
|
||||||
self.components.iter()
|
self.components.iter()
|
||||||
|
|
|
@ -1320,6 +1320,23 @@ impl World {
|
||||||
.map(Into::into)
|
.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.
|
/// Initializes a new resource and returns the [`ComponentId`] created for it.
|
||||||
///
|
///
|
||||||
/// If the resource already exists, nothing happens.
|
/// 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]
|
#[test]
|
||||||
fn custom_resource_with_layout() {
|
fn custom_resource_with_layout() {
|
||||||
static DROP_COUNT: AtomicU32 = AtomicU32::new(0);
|
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];
|
let value: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
|
||||||
OwningPtr::make(value, |ptr| {
|
OwningPtr::make(value, |ptr| {
|
||||||
|
|
Loading…
Reference in a new issue