Skip to content

Instantly share code, notes, and snippets.

@Multirious
Last active May 12, 2024 11:02
Show Gist options
  • Save Multirious/ff049b368cfe7e9df130bdf59f14e777 to your computer and use it in GitHub Desktop.
Save Multirious/ff049b368cfe7e9df130bdf59f14e777 to your computer and use it in GitHub Desktop.
bevy_clone_entity_recursive
// Bevy version: 0.10
use bevy::{prelude::*, ecs::system::Command};
// Copy all components from an entity to another.
// Using an entity with no components as the destination creates a copy of the source entity.
// panics if
// - the components are not registered in the type registry,
// - the world does not have a type registry
// - the source or destination entity do not exist
pub fn clone_entity_components(
world: &mut World,
source: Entity,
destination: Entity,
) {
let wc = world.as_unsafe_world_cell();
unsafe {
let registry = wc.world().get_resource::<AppTypeRegistry>().unwrap();
let type_registry = registry.read();
let entity_ref = wc.world().get_entity(source).unwrap();
let archetype = entity_ref.archetype();
let components = wc.world().components();
for component_id in archetype.components() {
let component_info = components.get_info(component_id).unwrap();
let type_id = component_info.type_id().unwrap();
if TypeId::of::<Children>() == type_id || TypeId::of::<Parent>() == type_id {
continue;
}
let registration =
type_registry.get(type_id).unwrap_or_else(|| {
panic!(
"expected {} to be registered to type registry",
component_info.name()
)
});
// here is where the magic happens
let reflect_component =
registration.data::<ReflectComponent>().unwrap();
reflect_component.copy(
wc.world_mut(),
wc.world_mut(),
source,
destination,
);
}
}
}
/// Clone entity including their children.
pub fn clone_entity_recursive(
world: &mut World,
source: Entity,
destination: Entity,
) {
clone_entity_components(world, source, destination);
let source = world.get_entity(source).unwrap();
let source_children = match source.get::<Children>() {
Some(o) => o,
None => return,
};
let source_children: Vec<Entity> =
source_children.iter().copied().collect();
for child in source_children {
let child_cloned = world.spawn_empty().id();
clone_entity_recursive(world, child, child_cloned);
world
.get_entity_mut(destination)
.unwrap()
.add_child(child_cloned);
}
}
// this allows the command to be used in systems
pub struct CloneEntity(pub Entity, pub Entity);
impl Command for CloneEntity {
fn write(self, world: &mut World) {
clone_entity_components(world, self.0, self.1);
}
}
pub struct CloneEntityRecursive(pub Entity, pub Entity);
impl Command for CloneEntityRecursive {
fn apply(self, world: &mut World) {
clone_entity_recursive(world, self.0, self.1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment