
# 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>
1.7 KiB
title | pull_requests | |
---|---|---|
Relationship method set_risky |
|
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
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:
#[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.