bevy/crates
rewin 8bf5d99d86
Add method to remove component and all required components for removed component (#15026)
## Objective
The new Required Components feature (#14791) in Bevy allows spawning a
fixed set of components with a single method with cool require macro.
However, there's currently no corresponding method to remove all those
components together. This makes it challenging to keep insertion and
removal code in sync, especially for simple using cases.
```rust
#[derive(Component)]
#[require(Y)]
struct X;

#[derive(Component, Default)]
struct Y;

world.entity_mut(e).insert(X); // Spawns both X and Y
world.entity_mut(e).remove::<X>(); 
world.entity_mut(e).remove::<Y>(); // We need to manually remove dependencies without any sync with the `require` macro
```
## Solution
Simplifies component management by providing operations for removal
required components.
This PR introduces simple 'footgun' methods to removes all components of
this bundle and its required components.

Two new methods are introduced:
For Commands:
```rust
commands.entity(e).remove_with_requires::<B>();
```
For World:
```rust
world.entity_mut(e).remove_with_requires::<B>();
```

For performance I created new field in Bundels struct. This new field
"contributed_bundle_ids" contains cached ids for dynamic bundles
constructed from bundle_info.cintributed_components()

## Testing
The PR includes three test cases:

1. Removing a single component with requirements using World.
2. Removing a bundle with requirements using World.
3. Removing a single component with requirements using Commands.
4. Removing a single component with **runtime** requirements using
Commands

These tests ensure the feature works as expected across different
scenarios.

## Showcase
Example:
```rust
use bevy_ecs::prelude::*;

#[derive(Component)]
#[require(Y)]
struct X;

#[derive(Component, Default)]
#[require(Z)]
struct Y;

#[derive(Component, Default)]
struct Z;

#[derive(Component)]
struct W;

let mut world = World::new();

// Spawn an entity with X, Y, Z, and W components
let entity = world.spawn((X, W)).id();

assert!(world.entity(entity).contains::<X>());
assert!(world.entity(entity).contains::<Y>());
assert!(world.entity(entity).contains::<Z>());
assert!(world.entity(entity).contains::<W>());

// Remove X and required components Y, Z
world.entity_mut(entity).remove_with_requires::<X>();

assert!(!world.entity(entity).contains::<X>());
assert!(!world.entity(entity).contains::<Y>());
assert!(!world.entity(entity).contains::<Z>());

assert!(world.entity(entity).contains::<W>());
```

## Motivation for PR
#15580 

## Performance

I made simple benchmark
```rust
let mut world = World::default();
let entity = world.spawn_empty().id();

let steps = 100_000_000;

let start = std::time::Instant::now();
for _ in 0..steps {
    world.entity_mut(entity).insert(X);
    world.entity_mut(entity).remove::<(X, Y, Z, W)>();
}
let end = std::time::Instant::now();
println!("normal remove: {:?} ", (end - start).as_secs_f32());
println!("one remove: {:?} micros", (end - start).as_secs_f64() / steps as f64 * 1_000_000.0);

let start = std::time::Instant::now();
for _ in 0..steps {
    world.entity_mut(entity).insert(X);
    world.entity_mut(entity).remove_with_requires::<X>();
}
let end = std::time::Instant::now();
println!("remove_with_requires: {:?} ", (end - start).as_secs_f32());
println!("one remove_with_requires: {:?} micros", (end - start).as_secs_f64() / steps as f64 * 1_000_000.0);
```

Output:

CPU: Amd Ryzen 7 2700x

```bash
normal remove: 17.36135 
one remove: 0.17361348299999999 micros
remove_with_requires: 17.534006 
one remove_with_requires: 0.17534005400000002 micros
```

NOTE: I didn't find any tests or mechanism in the repository to update
BundleInfo after creating new runtime requirements with an existing
BundleInfo. So this PR also does not contain such logic.

## Future work (outside this PR)

Create cache system for fast removing components in "safe" mode, where
"safe" mode is remove only required components that will be no longer
required after removing root component.

---------

Co-authored-by: a.yamaev <a.yamaev@smartengines.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-10-03 20:35:08 +00:00
..
bevy_a11y Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
bevy_animation Eliminate redundant clamping from sample-interpolated curves (#15620) 2024-10-03 18:26:41 +00:00
bevy_app Documentation for variadics (#15387) 2024-10-02 12:48:36 +00:00
bevy_asset move ANDROID_APP to bevy_window (#15585) 2024-10-02 03:01:06 +00:00
bevy_audio Migrate audio to required components (#15573) 2024-10-01 22:43:29 +00:00
bevy_color Eliminate redundant clamping from sample-interpolated curves (#15620) 2024-10-03 18:26:41 +00:00
bevy_core Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
bevy_core_pipeline Migrate motion blur, TAA, SSAO, and SSR to required components (#15572) 2024-10-01 22:45:31 +00:00
bevy_derive move ANDROID_APP to bevy_window (#15585) 2024-10-02 03:01:06 +00:00
bevy_dev_tools send_events is ambiguous_with_all (#15629) 2024-10-03 20:02:52 +00:00
bevy_diagnostic Runtime required components (#15458) 2024-09-30 19:20:16 +00:00
bevy_dylib Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965) 2024-07-29 23:10:16 +00:00
bevy_ecs Add method to remove component and all required components for removed component (#15026) 2024-10-03 20:35:08 +00:00
bevy_encase_derive Update `glam to 0.29, encase` to 0.10. (#15249) 2024-09-23 19:44:02 +00:00
bevy_gilrs Implement gamepads as entities (#12770) 2024-09-27 20:07:20 +00:00
bevy_gizmos Use circle gizmos for capsule (#15602) 2024-10-02 19:47:56 +00:00
bevy_gltf Migrate scenes to required components (#15579) 2024-10-01 22:42:11 +00:00
bevy_hierarchy Add try_despawn methods to World/Commands (#15480) 2024-10-03 16:21:05 +00:00
bevy_input Revert "Have EntityCommands methods consume self for easier chaining" (#15523) 2024-10-02 12:47:26 +00:00
bevy_internal Add features to switch NativeActivity and GameActivity usage (#12095) 2024-10-01 22:23:48 +00:00
bevy_log Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
bevy_macro_utils Modify derive_label to support no_std environments (#15465) 2024-09-27 20:23:26 +00:00
bevy_math Eliminate redundant clamping from sample-interpolated curves (#15620) 2024-10-03 18:26:41 +00:00
bevy_mikktspace Add no_std support to bevy_mikktspace (#15528) 2024-09-30 18:17:03 +00:00
bevy_pbr Added visibility bitmask as an alternative SSAO method (#13454) 2024-10-02 13:43:35 +00:00
bevy_picking Rename observe to observe_entity on EntityWorldMut (#15616) 2024-10-03 17:05:26 +00:00
bevy_ptr Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
bevy_reflect Documentation for variadics (#15387) 2024-10-02 12:48:36 +00:00
bevy_remote Allow access a method handler (#15601) 2024-10-02 19:45:18 +00:00
bevy_render Better warnings about invalid parameters (#15500) 2024-10-03 13:16:55 +00:00
bevy_scene Migrate scenes to required components (#15579) 2024-10-01 22:42:11 +00:00
bevy_sprite Revert "Have EntityCommands methods consume self for easier chaining" (#15523) 2024-10-02 12:47:26 +00:00
bevy_state Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
bevy_tasks bump async-channel to 2.3.0 (#15497) 2024-09-28 19:21:59 +00:00
bevy_text Fix extract_text2d_sprite entity leak (#15625) 2024-10-03 18:15:36 +00:00
bevy_time Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
bevy_transform Migrate visibility to required components (#15474) 2024-09-27 19:06:16 +00:00
bevy_ui Fix entity leak in extract_uinode_borders (#15626) 2024-10-03 18:15:32 +00:00
bevy_utils Add core and alloc over std Lints (#15281) 2024-09-27 00:59:59 +00:00
bevy_window move ANDROID_APP to bevy_window (#15585) 2024-10-02 03:01:06 +00:00
bevy_winit move ANDROID_APP to bevy_window (#15585) 2024-10-02 03:01:06 +00:00