From 9f5345fe9dfffcdc60c0174c7d10e61d521ec072 Mon Sep 17 00:00:00 2001 From: Joda Date: Tue, 16 Sep 2025 06:02:41 -0500 Subject: [PATCH] Guard against VisibilityClass being duplicated while cloning Co-authored-by: Dimitrios Loukadakis --- crates/bevy_camera/src/visibility/mod.rs | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/bevy_camera/src/visibility/mod.rs b/crates/bevy_camera/src/visibility/mod.rs index 8ac0ea4fe565d..c4e313428a9c6 100644 --- a/crates/bevy_camera/src/visibility/mod.rs +++ b/crates/bevy_camera/src/visibility/mod.rs @@ -150,11 +150,16 @@ impl InheritedVisibility { /// When adding a new renderable component, you'll typically want to write an /// add-component hook that adds the type ID of that component to the /// [`VisibilityClass`] array. See `custom_phase_item` for an example. +/// +/// `VisibilityClass` is automatically added by a hook on the `Mesh3d` and +/// `Mesh2d` components. To avoid duplicating the `VisibilityClass` and +/// causing issues when cloning, we use `#[component(clone_behavior=Ignore)]` // // Note: This can't be a `ComponentId` because the visibility classes are copied // into the render world, and component IDs are per-world. #[derive(Clone, Component, Default, Reflect, Deref, DerefMut)] #[reflect(Component, Default, Clone)] +#[component(clone_behavior=Ignore)] pub struct VisibilityClass(pub SmallVec<[TypeId; 1]>); /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering. @@ -988,4 +993,27 @@ mod test { assert_eq!(1, size_of::()); assert_eq!(1, size_of::>()); } + + #[derive(Component, Default, Clone, Reflect)] + #[require(VisibilityClass)] + #[reflect(Component, Default, Clone)] + #[component(on_add = add_visibility_class::)] + struct TestVisibilityClassHook; + + #[test] + fn test_add_visibility_class_hook() { + let mut world = World::new(); + let entity = world.spawn(TestVisibilityClassHook).id(); + let entity_clone = world.spawn_empty().id(); + world + .entity_mut(entity) + .clone_with_opt_out(entity_clone, |_| {}); + + let entity_visibility_class = world.entity(entity).get::().unwrap(); + assert_eq!(entity_visibility_class.len(), 1); + + let entity_clone_visibility_class = + world.entity(entity_clone).get::().unwrap(); + assert_eq!(entity_clone_visibility_class.len(), 1); + } }