Skip to content

Commit 2e267bb

Browse files
authored
Entity cloning (#16132)
## Objective Fixes #1515 This PR implements a flexible entity cloning system. The primary use case for it is to clone dynamically-generated entities. Example: ```rs #[derive(Component, Clone)] pub struct Projectile; #[derive(Component, Clone)] pub struct Damage { value: f32, } fn player_input( mut commands: Commands, projectiles: Query<Entity, With<Projectile>>, input: Res<ButtonInput<KeyCode>>, ) { // Fire a projectile if input.just_pressed(KeyCode::KeyF) { commands.spawn((Projectile, Damage { value: 10.0 })); } // Triplicate all active projectiles if input.just_pressed(KeyCode::KeyT) { for projectile in projectiles.iter() { // To triplicate a projectile we need to create 2 more clones for _ in 0..2{ commands.clone_entity(projectile) } } } } ``` ## Solution ### Commands Add a `clone_entity` command to create a clone of an entity with all components that can be cloned. Components that can't be cloned will be ignored. ```rs commands.clone_entity(entity) ``` If there is a need to configure the cloning process (like set to clone recursively), there is a second command: ```rs commands.clone_entity_with(entity, |builder| { builder.recursive(true) }); ``` Both of these commands return `EntityCommands` of the cloned entity, so the copy can be modified afterwards. ### Builder All these commands use `EntityCloneBuilder` internally. If there is a need to clone an entity using `World` instead, it is also possible: ```rs let entity = world.spawn(Component).id(); let entity_clone = world.spawn_empty().id(); EntityCloneBuilder::new(&mut world).clone_entity(entity, entity_clone); ``` Builder has methods to `allow` or `deny` certain components during cloning if required and can be extended by implementing traits on it. This PR includes two `EntityCloneBuilder` extensions: `CloneEntityWithObserversExt` to configure adding cloned entity to observers of the original entity, and `CloneEntityRecursiveExt` to configure cloning an entity recursively. ### Clone implementations By default, all components that implement either `Clone` or `Reflect` will be cloned (with `Clone`-based implementation preferred in case component implements both). This can be overriden on a per-component basis: ```rs impl Component for SomeComponent { const STORAGE_TYPE: StorageType = StorageType::Table; fn get_component_clone_handler() -> ComponentCloneHandler { // Don't clone this component ComponentCloneHandler::Ignore } } ``` ### `ComponentCloneHandlers` Clone implementation specified in `get_component_clone_handler` will get registered in `ComponentCloneHandlers` (stored in `bevy_ecs::component::Components`) at component registration time. The clone handler implementation provided by a component can be overriden after registration like so: ```rs let component_id = world.components().component_id::<Component>().unwrap() world.get_component_clone_handlers_mut() .set_component_handler(component_id, ComponentCloneHandler::Custom(component_clone_custom)) ``` The default clone handler for all components that do not explicitly define one (or don't derive `Component`) is `component_clone_via_reflect` if `bevy_reflect` feature is enabled, and `component_clone_ignore` (noop) otherwise. Default handler can be overriden using `ComponentCloneHandlers::set_default_handler` ### Handlers Component clone handlers can be used to modify component cloning behavior. The general signature for a handler that can be used in `ComponentCloneHandler::Custom` is as follows: ```rs pub fn component_clone_custom( world: &mut DeferredWorld, entity_cloner: &EntityCloner, ) { // implementation } ``` The `EntityCloner` implementation (used internally by `EntityCloneBuilder`) assumes that after calling this custom handler, the `target` entity has the desired version of the component from the `source` entity. ### Builder handler overrides Besides component-defined and world-overriden handlers, `EntityCloneBuilder` also has a way to override handlers locally. It is mainly used to allow configuration methods like `recursive` and `add_observers`. ```rs // From observer clone handler implementation impl CloneEntityWithObserversExt for EntityCloneBuilder<'_> { fn add_observers(&mut self, add_observers: bool) -> &mut Self { if add_observers { self.override_component_clone_handler::<ObservedBy>(ComponentCloneHandler::Custom( component_clone_observed_by, )) } else { self.remove_component_clone_handler_override::<ObservedBy>() } } } ``` ## Testing Includes some basic functionality tests and doctests. Performance-wise this feature is the same as calling `clone` followed by `insert` for every entity component. There is also some inherent overhead due to every component clone handler having to access component data through `World`, but this can be reduced without breaking current public API in a later PR.
1 parent d221665 commit 2e267bb

File tree

12 files changed

+1111
-14
lines changed

12 files changed

+1111
-14
lines changed

crates/bevy_ecs/macros/src/component.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
163163
#on_replace
164164
#on_remove
165165
}
166+
167+
fn get_component_clone_handler() -> #bevy_ecs_path::component::ComponentCloneHandler {
168+
use #bevy_ecs_path::component::{ComponentCloneViaClone, ComponentCloneBase};
169+
(&&&#bevy_ecs_path::component::ComponentCloneSpecializationWrapper::<Self>::default())
170+
.get_component_clone_handler()
171+
}
166172
}
167173
})
168174
}

crates/bevy_ecs/src/component.rs

Lines changed: 200 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
archetype::ArchetypeFlags,
66
bundle::BundleInfo,
77
change_detection::MAX_CHANGE_AGE,
8-
entity::Entity,
8+
entity::{Entity, EntityCloner},
99
query::DebugCheckedUnwrap,
1010
storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow},
1111
system::{Local, Resource, SystemParam},
@@ -390,6 +390,13 @@ pub trait Component: Send + Sync + 'static {
390390
_inheritance_depth: u16,
391391
) {
392392
}
393+
394+
/// Called when registering this component, allowing to override clone function (or disable cloning altogether) for this component.
395+
///
396+
/// See [Handlers section of `EntityCloneBuilder`](crate::entity::EntityCloneBuilder#handlers) to understand how this affects handler priority.
397+
fn get_component_clone_handler() -> ComponentCloneHandler {
398+
ComponentCloneHandler::default()
399+
}
393400
}
394401

395402
/// The storage used for a specific component type.
@@ -875,12 +882,96 @@ impl ComponentDescriptor {
875882
}
876883
}
877884

885+
/// Function type that can be used to clone an entity.
886+
pub type ComponentCloneFn = fn(&mut DeferredWorld, &EntityCloner);
887+
888+
/// An enum instructing how to clone a component.
889+
#[derive(Debug, Default)]
890+
pub enum ComponentCloneHandler {
891+
#[default]
892+
/// Use the global default function to clone the component with this handler.
893+
Default,
894+
/// Do not clone the component. When a command to clone an entity is issued, component with this handler will be skipped.
895+
Ignore,
896+
/// Set a custom handler for the component.
897+
Custom(ComponentCloneFn),
898+
}
899+
900+
/// A registry of component clone handlers. Allows to set global default and per-component clone function for all components in the world.
901+
#[derive(Debug)]
902+
pub struct ComponentCloneHandlers {
903+
handlers: Vec<Option<ComponentCloneFn>>,
904+
default_handler: ComponentCloneFn,
905+
}
906+
907+
impl ComponentCloneHandlers {
908+
/// Sets the default handler for this registry. All components with [`Default`](ComponentCloneHandler::Default) handler, as well as any component that does not have an
909+
/// explicitly registered clone function will use this handler.
910+
///
911+
/// See [Handlers section of `EntityCloneBuilder`](crate::entity::EntityCloneBuilder#handlers) to understand how this affects handler priority.
912+
pub fn set_default_handler(&mut self, handler: ComponentCloneFn) {
913+
self.default_handler = handler;
914+
}
915+
916+
/// Returns the currently registered default handler.
917+
pub fn get_default_handler(&self) -> ComponentCloneFn {
918+
self.default_handler
919+
}
920+
921+
/// Sets a handler for a specific component.
922+
///
923+
/// See [Handlers section of `EntityCloneBuilder`](crate::entity::EntityCloneBuilder#handlers) to understand how this affects handler priority.
924+
pub fn set_component_handler(&mut self, id: ComponentId, handler: ComponentCloneHandler) {
925+
if id.0 >= self.handlers.len() {
926+
self.handlers.resize(id.0 + 1, None);
927+
}
928+
match handler {
929+
ComponentCloneHandler::Default => self.handlers[id.0] = None,
930+
ComponentCloneHandler::Ignore => self.handlers[id.0] = Some(component_clone_ignore),
931+
ComponentCloneHandler::Custom(handler) => self.handlers[id.0] = Some(handler),
932+
};
933+
}
934+
935+
/// Checks if the specified component is registered. If not, the component will use the default global handler.
936+
///
937+
/// This will return an incorrect result if `id` did not come from the same world as `self`.
938+
pub fn is_handler_registered(&self, id: ComponentId) -> bool {
939+
self.handlers.get(id.0).is_some_and(Option::is_some)
940+
}
941+
942+
/// Gets a handler to clone a component. This can be one of the following:
943+
/// - Custom clone function for this specific component.
944+
/// - Default global handler.
945+
/// - A [`component_clone_ignore`] (no cloning).
946+
///
947+
/// This will return an incorrect result if `id` did not come from the same world as `self`.
948+
pub fn get_handler(&self, id: ComponentId) -> ComponentCloneFn {
949+
match self.handlers.get(id.0) {
950+
Some(Some(handler)) => *handler,
951+
Some(None) | None => self.default_handler,
952+
}
953+
}
954+
}
955+
956+
impl Default for ComponentCloneHandlers {
957+
fn default() -> Self {
958+
Self {
959+
handlers: Default::default(),
960+
#[cfg(feature = "bevy_reflect")]
961+
default_handler: component_clone_via_reflect,
962+
#[cfg(not(feature = "bevy_reflect"))]
963+
default_handler: component_clone_ignore,
964+
}
965+
}
966+
}
967+
878968
/// Stores metadata associated with each kind of [`Component`] in a given [`World`].
879969
#[derive(Debug, Default)]
880970
pub struct Components {
881971
components: Vec<ComponentInfo>,
882972
indices: TypeIdMap<ComponentId>,
883973
resource_indices: TypeIdMap<ComponentId>,
974+
component_clone_handlers: ComponentCloneHandlers,
884975
}
885976

886977
impl Components {
@@ -918,6 +1009,9 @@ impl Components {
9181009
let info = &mut self.components[id.index()];
9191010
T::register_component_hooks(&mut info.hooks);
9201011
info.required_components = required_components;
1012+
let clone_handler = T::get_component_clone_handler();
1013+
self.component_clone_handlers
1014+
.set_component_handler(id, clone_handler);
9211015
}
9221016
id
9231017
}
@@ -1276,6 +1370,16 @@ impl Components {
12761370
.map(|info| &mut info.required_by)
12771371
}
12781372

1373+
/// Retrieves the [`ComponentCloneHandlers`]. Can be used to get clone functions for components.
1374+
pub fn get_component_clone_handlers(&self) -> &ComponentCloneHandlers {
1375+
&self.component_clone_handlers
1376+
}
1377+
1378+
/// Retrieves a mutable reference to the [`ComponentCloneHandlers`]. Can be used to set and update clone functions for components.
1379+
pub fn get_component_clone_handlers_mut(&mut self) -> &mut ComponentCloneHandlers {
1380+
&mut self.component_clone_handlers
1381+
}
1382+
12791383
/// Type-erased equivalent of [`Components::component_id()`].
12801384
#[inline]
12811385
pub fn get_id(&self, type_id: TypeId) -> Option<ComponentId> {
@@ -1853,3 +1957,98 @@ impl RequiredComponents {
18531957
}
18541958
}
18551959
}
1960+
1961+
/// Component [clone handler function](ComponentCloneFn) implemented using the [`Clone`] trait.
1962+
/// Can be [set](ComponentCloneHandlers::set_component_handler) as clone handler for the specific component it is implemented for.
1963+
/// It will panic if set as handler for any other component.
1964+
///
1965+
/// See [`ComponentCloneHandlers`] for more details.
1966+
pub fn component_clone_via_clone<C: Clone + Component>(
1967+
world: &mut DeferredWorld,
1968+
entity_cloner: &EntityCloner,
1969+
) {
1970+
let component = world
1971+
.entity(entity_cloner.source())
1972+
.get::<C>()
1973+
.expect("Component must exists on source entity")
1974+
.clone();
1975+
world
1976+
.commands()
1977+
.entity(entity_cloner.target())
1978+
.insert(component);
1979+
}
1980+
1981+
/// Component [clone handler function](ComponentCloneFn) implemented using reflect.
1982+
/// Can be [set](ComponentCloneHandlers::set_component_handler) as clone handler for any registered component,
1983+
/// but only reflected components will be cloned.
1984+
///
1985+
/// See [`ComponentCloneHandlers`] for more details.
1986+
#[cfg(feature = "bevy_reflect")]
1987+
pub fn component_clone_via_reflect(world: &mut DeferredWorld, entity_cloner: &EntityCloner) {
1988+
let component_id = entity_cloner.component_id();
1989+
let source = entity_cloner.source();
1990+
let target = entity_cloner.target();
1991+
world.commands().queue(move |world: &mut World| {
1992+
world.resource_scope::<crate::reflect::AppTypeRegistry, ()>(|world, registry| {
1993+
let registry = registry.read();
1994+
1995+
let component_info = world
1996+
.components()
1997+
.get_info(component_id)
1998+
.expect("Component must be registered");
1999+
let Some(type_id) = component_info.type_id() else {
2000+
return;
2001+
};
2002+
let Some(reflect_component) =
2003+
registry.get_type_data::<crate::reflect::ReflectComponent>(type_id)
2004+
else {
2005+
return;
2006+
};
2007+
let source_component = reflect_component
2008+
.reflect(world.get_entity(source).expect("Source entity must exist"))
2009+
.expect("Source entity must have reflected component")
2010+
.clone_value();
2011+
let mut target = world
2012+
.get_entity_mut(target)
2013+
.expect("Target entity must exist");
2014+
reflect_component.apply_or_insert(&mut target, &*source_component, &registry);
2015+
});
2016+
});
2017+
}
2018+
2019+
/// Noop implementation of component clone handler function.
2020+
///
2021+
/// See [`ComponentCloneHandlers`] for more details.
2022+
pub fn component_clone_ignore(_world: &mut DeferredWorld, _entity_cloner: &EntityCloner) {}
2023+
2024+
/// Wrapper for components clone specialization using autoderef.
2025+
#[doc(hidden)]
2026+
pub struct ComponentCloneSpecializationWrapper<T>(PhantomData<T>);
2027+
2028+
impl<T> Default for ComponentCloneSpecializationWrapper<T> {
2029+
fn default() -> Self {
2030+
Self(PhantomData)
2031+
}
2032+
}
2033+
2034+
/// Base trait for components clone specialization using autoderef.
2035+
#[doc(hidden)]
2036+
pub trait ComponentCloneBase {
2037+
fn get_component_clone_handler(&self) -> ComponentCloneHandler;
2038+
}
2039+
impl<C: Component> ComponentCloneBase for ComponentCloneSpecializationWrapper<C> {
2040+
fn get_component_clone_handler(&self) -> ComponentCloneHandler {
2041+
ComponentCloneHandler::default()
2042+
}
2043+
}
2044+
2045+
/// Specialized trait for components clone specialization using autoderef.
2046+
#[doc(hidden)]
2047+
pub trait ComponentCloneViaClone {
2048+
fn get_component_clone_handler(&self) -> ComponentCloneHandler;
2049+
}
2050+
impl<C: Clone + Component> ComponentCloneViaClone for &ComponentCloneSpecializationWrapper<C> {
2051+
fn get_component_clone_handler(&self) -> ComponentCloneHandler {
2052+
ComponentCloneHandler::Custom(component_clone_via_clone::<C>)
2053+
}
2054+
}

0 commit comments

Comments
 (0)