Skip to content

Instantly share code, notes, and snippets.

@nwtnni
Forked from GianpaoloBranca/cloneEntity.rs
Last active April 23, 2024 14:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nwtnni/85d6b87ae75337a522166c500c9a8418 to your computer and use it in GitHub Desktop.
Save nwtnni/85d6b87ae75337a522166c500c9a8418 to your computer and use it in GitHub Desktop.
Copy all components from an Entity to another in Bevy
//! Bevy Version: 0.10
//! Original: https://gist.github.com/GianpaoloBranca/17e5bd6ada9bdb04cca58182db8505d4
//! See also: https://github.com/bevyengine/bevy/issues/1515
use bevy::ecs::system::Command;
use bevy::prelude::*;
pub struct CloneEntity {
pub source: Entity,
pub destination: Entity,
}
impl CloneEntity {
// 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
fn clone_entity(self, world: &mut World) {
let components = {
let registry = world.get_resource::<AppTypeRegistry>().unwrap().read();
world
.get_entity(self.source)
.unwrap()
.archetype()
.components()
.map(|component_id| {
world
.components()
.get_info(component_id)
.unwrap()
.type_id()
.unwrap()
})
.map(|type_id| {
registry
.get(type_id)
.unwrap()
.data::<ReflectComponent>()
.unwrap()
.clone()
})
.collect::<Vec<_>>()
};
for component in components {
let source = component
.reflect(world.get_entity(self.source).unwrap())
.unwrap()
.clone_value();
let mut destination = world.get_entity_mut(self.destination).unwrap();
component.apply_or_insert(&mut destination, &*source);
}
}
}
// This allows the command to be used in systems
impl Command for CloneEntity {
fn write(self, world: &mut World) {
self.clone_entity(world)
}
}
// **********************************************************
// Adapt the code below to your needs
// **********************************************************
// Components must derive Reflect and use reflect(Component)
// If your component includes some other structs, these have to derive from Reflect and FromReflect
#[derive(Component, Reflect, Default)]
#[reflect(Component)]
pub struct Foo {
pub bar: i32,
pub baz: bool,
}
// In your system, clone an entity like this:
fn clone_entity(mut commands: Commands /* whatever you want that gets your entity */) {
// your code here to fetch the source entity
// ...
let copy = commands.spawn_empty().id();
commands.add(CloneEntity {
source: entity,
destination: copy,
});
}
// Also, remember to register your components in the App Type Registry!
// Some predefined components are already registered (e.g. Name)
// You can write your own plugin where you put all your registrations
fn main() {
let mut app = App::new();
{
let registry = app.world.resource_mut::<AppTypeRegistry>();
let mut wr = registry.write();
wr.register::<Foo>();
// other structs...
}
app.run()
}
@blueforesticarus
Copy link

insert_or_apply now takes a TypeRegistry so I had to make the following adjustment

let registry = world.get_resource::<AppTypeRegistry>().unwrap().internal.to_owned();
let mut destination = world.get_entity_mut(self.destination).unwrap();
component.apply_or_insert(&mut destination, &*source, &registry.read().unwrap());

not too happy about that to_owned, but without cloning the arc I hit the borrow checker due to the &mut destination

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment