Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/component/clone.rs
6600 views
1
use core::marker::PhantomData;
2
3
use crate::component::Component;
4
use crate::entity::{ComponentCloneCtx, SourceComponent};
5
6
/// Function type that can be used to clone a component of an entity.
7
pub type ComponentCloneFn = fn(&SourceComponent, &mut ComponentCloneCtx);
8
9
/// The clone behavior to use when cloning or moving a [`Component`].
10
#[derive(Clone, Debug, Default)]
11
pub enum ComponentCloneBehavior {
12
/// Uses the default behavior (which is passed to [`ComponentCloneBehavior::resolve`])
13
#[default]
14
Default,
15
/// Do not clone/move this component.
16
Ignore,
17
/// Uses a custom [`ComponentCloneFn`].
18
Custom(ComponentCloneFn),
19
}
20
21
impl ComponentCloneBehavior {
22
/// Set clone handler based on `Clone` trait.
23
///
24
/// If set as a handler for a component that is not the same as the one used to create this handler, it will panic.
25
pub fn clone<C: Component + Clone>() -> Self {
26
Self::Custom(component_clone_via_clone::<C>)
27
}
28
29
/// Set clone handler based on `Reflect` trait.
30
#[cfg(feature = "bevy_reflect")]
31
pub fn reflect() -> Self {
32
Self::Custom(component_clone_via_reflect)
33
}
34
35
/// Returns the "global default"
36
pub fn global_default_fn() -> ComponentCloneFn {
37
#[cfg(feature = "bevy_reflect")]
38
return component_clone_via_reflect;
39
#[cfg(not(feature = "bevy_reflect"))]
40
return component_clone_ignore;
41
}
42
43
/// Resolves the [`ComponentCloneBehavior`] to a [`ComponentCloneFn`]. If [`ComponentCloneBehavior::Default`] is
44
/// specified, the given `default` function will be used.
45
pub fn resolve(&self, default: ComponentCloneFn) -> ComponentCloneFn {
46
match self {
47
ComponentCloneBehavior::Default => default,
48
ComponentCloneBehavior::Ignore => component_clone_ignore,
49
ComponentCloneBehavior::Custom(custom) => *custom,
50
}
51
}
52
}
53
54
/// Component [clone handler function](ComponentCloneFn) implemented using the [`Clone`] trait.
55
/// Can be [set](Component::clone_behavior) as clone handler for the specific component it is implemented for.
56
/// It will panic if set as handler for any other component.
57
///
58
pub fn component_clone_via_clone<C: Clone + Component>(
59
source: &SourceComponent,
60
ctx: &mut ComponentCloneCtx,
61
) {
62
if let Some(component) = source.read::<C>() {
63
ctx.write_target_component(component.clone());
64
}
65
}
66
67
/// Component [clone handler function](ComponentCloneFn) implemented using reflect.
68
/// Can be [set](Component::clone_behavior) as clone handler for any registered component,
69
/// but only reflected components will be cloned.
70
///
71
/// To clone a component using this handler, the following must be true:
72
/// - World has [`AppTypeRegistry`](crate::reflect::AppTypeRegistry)
73
/// - Component has [`TypeId`](core::any::TypeId)
74
/// - Component is registered
75
/// - Component has [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) registered
76
/// - Component can be cloned via [`PartialReflect::reflect_clone`] _or_ has one of the following registered: [`ReflectFromReflect`](bevy_reflect::ReflectFromReflect),
77
/// [`ReflectDefault`](bevy_reflect::std_traits::ReflectDefault), [`ReflectFromWorld`](crate::reflect::ReflectFromWorld)
78
///
79
/// If any of the conditions is not satisfied, the component will be skipped.
80
///
81
/// See [`EntityClonerBuilder`](crate::entity::EntityClonerBuilder) for details.
82
///
83
/// [`PartialReflect::reflect_clone`]: bevy_reflect::PartialReflect::reflect_clone
84
#[cfg(feature = "bevy_reflect")]
85
pub fn component_clone_via_reflect(source: &SourceComponent, ctx: &mut ComponentCloneCtx) {
86
let Some(app_registry) = ctx.type_registry().cloned() else {
87
return;
88
};
89
let registry = app_registry.read();
90
let Some(source_component_reflect) = source.read_reflect(&registry) else {
91
return;
92
};
93
let component_info = ctx.component_info();
94
// checked in read_source_component_reflect
95
let type_id = component_info.type_id().unwrap();
96
97
// Try to clone using `reflect_clone`
98
if let Ok(mut component) = source_component_reflect.reflect_clone() {
99
if let Some(reflect_component) =
100
registry.get_type_data::<crate::reflect::ReflectComponent>(type_id)
101
{
102
reflect_component.map_entities(&mut *component, ctx.entity_mapper());
103
}
104
drop(registry);
105
106
ctx.write_target_component_reflect(component);
107
return;
108
}
109
110
// Try to clone using ReflectFromReflect
111
if let Some(reflect_from_reflect) =
112
registry.get_type_data::<bevy_reflect::ReflectFromReflect>(type_id)
113
{
114
if let Some(mut component) =
115
reflect_from_reflect.from_reflect(source_component_reflect.as_partial_reflect())
116
{
117
if let Some(reflect_component) =
118
registry.get_type_data::<crate::reflect::ReflectComponent>(type_id)
119
{
120
reflect_component.map_entities(&mut *component, ctx.entity_mapper());
121
}
122
drop(registry);
123
124
ctx.write_target_component_reflect(component);
125
return;
126
}
127
}
128
// Else, try to clone using ReflectDefault
129
if let Some(reflect_default) =
130
registry.get_type_data::<bevy_reflect::std_traits::ReflectDefault>(type_id)
131
{
132
let mut component = reflect_default.default();
133
component.apply(source_component_reflect.as_partial_reflect());
134
drop(registry);
135
ctx.write_target_component_reflect(component);
136
return;
137
}
138
// Otherwise, try to clone using ReflectFromWorld
139
if let Some(reflect_from_world) =
140
registry.get_type_data::<crate::reflect::ReflectFromWorld>(type_id)
141
{
142
use crate::{entity::EntityMapper, world::World};
143
144
let reflect_from_world = reflect_from_world.clone();
145
let source_component_cloned = source_component_reflect.to_dynamic();
146
let component_layout = component_info.layout();
147
let target = ctx.target();
148
let component_id = ctx.component_id();
149
drop(registry);
150
ctx.queue_deferred(move |world: &mut World, mapper: &mut dyn EntityMapper| {
151
let mut component = reflect_from_world.from_world(world);
152
assert_eq!(type_id, (*component).type_id());
153
component.apply(source_component_cloned.as_partial_reflect());
154
if let Some(reflect_component) = app_registry
155
.read()
156
.get_type_data::<crate::reflect::ReflectComponent>(type_id)
157
{
158
reflect_component.map_entities(&mut *component, mapper);
159
}
160
// SAFETY:
161
// - component_id is from the same world as target entity
162
// - component is a valid value represented by component_id
163
unsafe {
164
use alloc::boxed::Box;
165
use bevy_ptr::OwningPtr;
166
167
let raw_component_ptr =
168
core::ptr::NonNull::new_unchecked(Box::into_raw(component).cast::<u8>());
169
world
170
.entity_mut(target)
171
.insert_by_id(component_id, OwningPtr::new(raw_component_ptr));
172
173
if component_layout.size() > 0 {
174
// Ensure we don't attempt to deallocate zero-sized components
175
alloc::alloc::dealloc(raw_component_ptr.as_ptr(), component_layout);
176
}
177
}
178
});
179
}
180
}
181
182
/// Noop implementation of component clone handler function.
183
///
184
/// See [`EntityClonerBuilder`](crate::entity::EntityClonerBuilder) for details.
185
pub fn component_clone_ignore(_source: &SourceComponent, _ctx: &mut ComponentCloneCtx) {}
186
187
/// Wrapper for components clone specialization using autoderef.
188
#[doc(hidden)]
189
pub struct DefaultCloneBehaviorSpecialization<T>(PhantomData<T>);
190
191
impl<T> Default for DefaultCloneBehaviorSpecialization<T> {
192
fn default() -> Self {
193
Self(PhantomData)
194
}
195
}
196
197
/// Base trait for components clone specialization using autoderef.
198
#[doc(hidden)]
199
pub trait DefaultCloneBehaviorBase {
200
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
201
}
202
203
impl<C> DefaultCloneBehaviorBase for DefaultCloneBehaviorSpecialization<C> {
204
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
205
ComponentCloneBehavior::Default
206
}
207
}
208
209
/// Specialized trait for components clone specialization using autoderef.
210
#[doc(hidden)]
211
pub trait DefaultCloneBehaviorViaClone {
212
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
213
}
214
215
impl<C: Clone + Component> DefaultCloneBehaviorViaClone for &DefaultCloneBehaviorSpecialization<C> {
216
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
217
ComponentCloneBehavior::clone::<C>()
218
}
219
}
220
221