Derive clone_behavior
for Components
(#18811)
Allow Derive(Component) to specify a clone_behavior ```rust #[derive(Component)] #[component(clone_behavior = Ignore)] MyComponent; ```
This commit is contained in:
parent
b19f644c2f
commit
60cdefd128
@ -251,6 +251,8 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
|
||||
|
||||
let clone_behavior = if relationship_target.is_some() {
|
||||
quote!(#bevy_ecs_path::component::ComponentCloneBehavior::Custom(#bevy_ecs_path::relationship::clone_relationship_target::<Self>))
|
||||
} else if let Some(behavior) = attrs.clone_behavior {
|
||||
quote!(#bevy_ecs_path::component::ComponentCloneBehavior::#behavior)
|
||||
} else {
|
||||
quote!(
|
||||
use #bevy_ecs_path::component::{DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone};
|
||||
@ -396,6 +398,7 @@ pub const ON_REMOVE: &str = "on_remove";
|
||||
pub const ON_DESPAWN: &str = "on_despawn";
|
||||
|
||||
pub const IMMUTABLE: &str = "immutable";
|
||||
pub const CLONE_BEHAVIOR: &str = "clone_behavior";
|
||||
|
||||
/// All allowed attribute value expression kinds for component hooks
|
||||
#[derive(Debug)]
|
||||
@ -458,6 +461,7 @@ struct Attrs {
|
||||
relationship: Option<Relationship>,
|
||||
relationship_target: Option<RelationshipTarget>,
|
||||
immutable: bool,
|
||||
clone_behavior: Option<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@ -496,6 +500,7 @@ fn parse_component_attr(ast: &DeriveInput) -> Result<Attrs> {
|
||||
relationship: None,
|
||||
relationship_target: None,
|
||||
immutable: false,
|
||||
clone_behavior: None,
|
||||
};
|
||||
|
||||
let mut require_paths = HashSet::new();
|
||||
@ -531,6 +536,9 @@ fn parse_component_attr(ast: &DeriveInput) -> Result<Attrs> {
|
||||
} else if nested.path.is_ident(IMMUTABLE) {
|
||||
attrs.immutable = true;
|
||||
Ok(())
|
||||
} else if nested.path.is_ident(CLONE_BEHAVIOR) {
|
||||
attrs.clone_behavior = Some(nested.value()?.parse()?);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(nested.error("Unsupported attribute"))
|
||||
}
|
||||
@ -560,6 +568,13 @@ fn parse_component_attr(ast: &DeriveInput) -> Result<Attrs> {
|
||||
}
|
||||
}
|
||||
|
||||
if attrs.relationship_target.is_some() && attrs.clone_behavior.is_some() {
|
||||
return Err(syn::Error::new(
|
||||
attrs.clone_behavior.span(),
|
||||
"A Relationship Target already has its own clone behavior, please remove `clone_behavior = ...`",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(attrs)
|
||||
}
|
||||
|
||||
|
@ -418,6 +418,21 @@ use thiserror::Error;
|
||||
/// println!("{message}");
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
/// # Setting the clone behavior
|
||||
///
|
||||
/// You can specify how the [`Component`] is cloned when deriving it.
|
||||
///
|
||||
/// Your options are the functions and variants of [`ComponentCloneBehavior`]
|
||||
/// See [Handlers section of `EntityClonerBuilder`](crate::entity::EntityClonerBuilder#handlers) to understand how this affects handler priority.
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
///
|
||||
/// #[derive(Component)]
|
||||
/// #[component(clone_behavior = Ignore)]
|
||||
/// struct MyComponent;
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
/// # Implementing the trait for foreign types
|
||||
|
@ -324,16 +324,10 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> {
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # use bevy_ecs::component::{StorageType, ComponentCloneBehavior, Mutable};
|
||||
/// #[derive(Clone)]
|
||||
/// #[derive(Clone, Component)]
|
||||
/// #[component(clone_behavior = clone::<Self>())]
|
||||
/// struct SomeComponent;
|
||||
///
|
||||
/// impl Component for SomeComponent {
|
||||
/// const STORAGE_TYPE: StorageType = StorageType::Table;
|
||||
/// type Mutability = Mutable;
|
||||
/// fn clone_behavior() -> ComponentCloneBehavior {
|
||||
/// ComponentCloneBehavior::clone::<Self>()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Clone Behaviors
|
||||
|
@ -2751,4 +2751,27 @@ mod tests {
|
||||
)]
|
||||
#[derive(Component)]
|
||||
struct MyEntitiesTuple(#[entities] Vec<Entity>, #[entities] Entity, usize);
|
||||
|
||||
#[test]
|
||||
fn clone_entities() {
|
||||
use crate::entity::{ComponentCloneCtx, SourceComponent};
|
||||
|
||||
#[derive(Component)]
|
||||
#[component(clone_behavior = Ignore)]
|
||||
struct IgnoreClone;
|
||||
|
||||
#[derive(Component)]
|
||||
#[component(clone_behavior = Default)]
|
||||
struct DefaultClone;
|
||||
|
||||
#[derive(Component)]
|
||||
#[component(clone_behavior = Custom(custom_clone))]
|
||||
struct CustomClone;
|
||||
|
||||
#[derive(Component, Clone)]
|
||||
#[component(clone_behavior = clone::<Self>())]
|
||||
struct CloneFunction;
|
||||
|
||||
fn custom_clone(_source: &SourceComponent, _ctx: &mut ComponentCloneCtx) {}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use bevy_app::Plugin;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::component::{ComponentCloneBehavior, Mutable, StorageType};
|
||||
use bevy_ecs::entity::EntityHash;
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
@ -127,7 +126,8 @@ pub struct SyncToRenderWorld;
|
||||
/// Component added on the main world entities that are synced to the Render World in order to keep track of the corresponding render world entity.
|
||||
///
|
||||
/// Can also be used as a newtype wrapper for render world entities.
|
||||
#[derive(Deref, Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Deref, Copy, Clone, Debug, Eq, Hash, PartialEq, Component)]
|
||||
#[component(clone_behavior = Ignore)]
|
||||
pub struct RenderEntity(Entity);
|
||||
impl RenderEntity {
|
||||
#[inline]
|
||||
@ -136,16 +136,6 @@ impl RenderEntity {
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for RenderEntity {
|
||||
const STORAGE_TYPE: StorageType = StorageType::Table;
|
||||
|
||||
type Mutability = Mutable;
|
||||
|
||||
fn clone_behavior() -> ComponentCloneBehavior {
|
||||
ComponentCloneBehavior::Ignore
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Entity> for RenderEntity {
|
||||
fn from(entity: Entity) -> Self {
|
||||
RenderEntity(entity)
|
||||
|
Loading…
Reference in New Issue
Block a user