Last active
May 12, 2024 11:02
-
-
Save Multirious/ff049b368cfe7e9df130bdf59f14e777 to your computer and use it in GitHub Desktop.
bevy_clone_entity_recursive
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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