Skip to content
53 changes: 28 additions & 25 deletions benches/benches/bevy_ecs/entity_cloning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use core::hint::black_box;

use benches::bench;
use bevy_ecs::bundle::Bundle;
use bevy_ecs::component::ComponentCloneHandler;
use bevy_ecs::component::ComponentCloneBehavior;
use bevy_ecs::entity::EntityCloner;
use bevy_ecs::hierarchy::ChildOf;
use bevy_ecs::reflect::AppTypeRegistry;
use bevy_ecs::{component::Component, world::World};
Expand Down Expand Up @@ -52,7 +53,10 @@ type ComplexBundle = (C1, C2, C3, C4, C5, C6, C7, C8, C9, C10);

/// Sets the [`ComponentCloneHandler`] for all explicit and required components in a bundle `B` to
/// use the [`Reflect`] trait instead of [`Clone`].
fn set_reflect_clone_handler<B: Bundle + GetTypeRegistration>(world: &mut World) {
fn reflection_cloner<B: Bundle + GetTypeRegistration>(
world: &mut World,
recursive: bool,
) -> EntityCloner {
// Get mutable access to the type registry, creating it if it does not exist yet.
let registry = world.get_resource_or_init::<AppTypeRegistry>();

Expand All @@ -67,12 +71,15 @@ fn set_reflect_clone_handler<B: Bundle + GetTypeRegistration>(world: &mut World)
// this bundle are saved.
let component_ids: Vec<_> = world.register_bundle::<B>().contributed_components().into();

let clone_handlers = world.get_component_clone_handlers_mut();
let mut builder = EntityCloner::build(world);

// Overwrite the clone handler for all components in the bundle to use `Reflect`, not `Clone`.
for component in component_ids {
clone_handlers.set_component_handler(component, ComponentCloneHandler::reflect_handler());
builder.override_clone_behavior_with_id(component, ComponentCloneBehavior::reflect());
}
builder.recursive(recursive);

builder.finish()
}

/// A helper function that benchmarks running the [`EntityCommands::clone_and_spawn()`] command on a
Expand All @@ -91,18 +98,18 @@ fn bench_clone<B: Bundle + Default + GetTypeRegistration>(
) {
let mut world = World::default();

if clone_via_reflect {
set_reflect_clone_handler::<B>(&mut world);
}
let mut cloner = if clone_via_reflect {
reflection_cloner::<B>(&mut world, false)
} else {
EntityCloner::default()
};

// Spawn the first entity, which will be cloned in the benchmark routine.
let id = world.spawn(B::default()).id();

b.iter(|| {
// Queue the command to clone the entity.
world.commands().entity(black_box(id)).clone_and_spawn();

// Run the command.
// clones the given entity
cloner.spawn_clone(&mut world, black_box(id));
world.flush();
});
}
Expand All @@ -125,9 +132,15 @@ fn bench_clone_hierarchy<B: Bundle + Default + GetTypeRegistration>(
) {
let mut world = World::default();

if clone_via_reflect {
set_reflect_clone_handler::<B>(&mut world);
}
let mut cloner = if clone_via_reflect {
reflection_cloner::<B>(&mut world, true)
} else {
let mut builder = EntityCloner::build(&mut world);
builder.recursive(true);
builder.finish()
};

// Make the clone command recursive, so children are cloned as well.

// Spawn the first entity, which will be cloned in the benchmark routine.
let id = world.spawn(B::default()).id();
Expand All @@ -148,18 +161,8 @@ fn bench_clone_hierarchy<B: Bundle + Default + GetTypeRegistration>(
}
}

// Flush all `set_parent()` commands.
world.flush();

b.iter(|| {
world
.commands()
.entity(black_box(id))
.clone_and_spawn_with(|builder| {
// Make the clone command recursive, so children are cloned as well.
builder.recursive(true);
});

cloner.spawn_clone(&mut world, black_box(id));
world.flush();
});
}
Expand Down
13 changes: 4 additions & 9 deletions crates/bevy_animation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,7 @@ use crate::{

use bevy_app::{Animation, App, Plugin, PostUpdate};
use bevy_asset::{Asset, AssetApp, AssetEvents, Assets};
use bevy_ecs::{
entity::{VisitEntities, VisitEntitiesMut},
prelude::*,
reflect::{ReflectMapEntities, ReflectVisitEntities, ReflectVisitEntitiesMut},
world::EntityMutExcept,
};
use bevy_ecs::{prelude::*, world::EntityMutExcept};
use bevy_math::FloatOrd;
use bevy_platform_support::{collections::HashMap, hash::NoOpHash};
use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath};
Expand Down Expand Up @@ -207,16 +202,16 @@ impl Hash for AnimationTargetId {
/// Note that each entity can only be animated by one animation player at a
/// time. However, you can change [`AnimationTarget`]'s `player` property at
/// runtime to change which player is responsible for animating the entity.
#[derive(Clone, Copy, Component, Reflect, VisitEntities, VisitEntitiesMut)]
#[reflect(Component, MapEntities, VisitEntities, VisitEntitiesMut)]
#[derive(Clone, Copy, Component, Reflect)]
#[reflect(Component)]
pub struct AnimationTarget {
/// The ID of this animation target.
///
/// Typically, this is derived from the path.
#[visit_entities(ignore)]
pub id: AnimationTargetId,

/// The entity containing the [`AnimationPlayer`].
#[entities]
pub player: Entity,
}

Expand Down
Loading