
# Objective Some methods and commands carelessly overwrite `Relationship` components. This may overwrite additional data stored at them which is undesired. Part of #19589 ## Solution A new private method will be used instead of insert: `modify_or_insert_relation_with_relationship_hook_mode`. This method behaves different to `insert` if `Relationship` is a larger type than `Entity` and already contains this component. It will then use the `modify_component` API and a new `Relationship::set_risky` method to set the related entity, keeping all other data untouched. For the `replace_related`(`_with_difference`) methods this also required a `InsertHookMode` parameter for efficient modifications of multiple children. The changes here are limited to the non-public methods. I would appreciate feedback if this is all good. # Testing Added tests of all methods that previously could reset `Relationship` data. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
42 lines
1.7 KiB
Markdown
42 lines
1.7 KiB
Markdown
---
|
|
title: Relationship method set_risky
|
|
pull_requests: [19601]
|
|
---
|
|
|
|
The trait `Relationship` received a new method, `set_risky`. It is used to alter the entity ID of the entity that contains its `RelationshipTarget` counterpart.
|
|
This is needed to leave [other data you can store in these components](https://docs.rs/bevy/latest/bevy/ecs/relationship/trait.Relationship.html#derive)
|
|
unchanged at operations that reassign the relationship target, for example `EntityCommands::add_related`. Previously this could have caused the
|
|
data to be reset to its default value which may not be what you wanted to happen.
|
|
|
|
Manually overwriting the component is still possible everywhere the full component is inserted:
|
|
|
|
```rs
|
|
#[derive(Component)]
|
|
#[relationship(relationship_target = CarOwner)]
|
|
struct OwnedCar {
|
|
#[relationship]
|
|
owner: Entity,
|
|
first_owner: Option<Entity>, // None if `owner` is the first one
|
|
}
|
|
|
|
#[derive(Component)]
|
|
#[relationship_target(relationship = OwnedCar)]
|
|
struct CarOwner(Vec<Entity>);
|
|
|
|
let mut me_entity_mut = world.entity_mut(me_entity);
|
|
|
|
// if `car_entity` already contains `OwnedCar`, then the first owner remains unchanged
|
|
me_entity_mut.add_one_related::<OwnedCar>(car_entity);
|
|
|
|
// if `car_entity` already contains `OwnedCar`, then the first owner is overwritten with None here
|
|
car_entity_mut.insert(OwnedCar {
|
|
owner: me_entity,
|
|
first_owner: None // I swear it is not stolen officer!
|
|
});
|
|
```
|
|
|
|
The new method should not be called by user code as that can invalidate the relationship it had or will have.
|
|
|
|
If you implement `Relationship` manually (which is strongly discouraged) then this method needs to overwrite the `Entity`
|
|
used for the relationship.
|