Skip to content

Conversation

@dmyyy
Copy link
Contributor

@dmyyy dmyyy commented Feb 28, 2025

Objective

Minimal implementation of directed one-to-one relationships via implementing RelationshipSourceCollection for Entity.

Now you can do

#[derive(Component)]
#[relationship(relationship_target = Below)]
pub struct Above(Entity);

#[derive(Component)]
#[relationship_target(relationship = Above)]
pub struct Below(Entity);

Future Work

It would be nice if the relationships could be fully symmetrical in the future - in the example above, since Above is the source of truth you can't add Below to an entity and have Above added automatically.

Testing

Wrote unit tests for new relationship sources and and verified adding/removing relationships maintains connection as expected.

@dmyyy dmyyy force-pushed the one_to_one_relationships branch from cb62c3e to ecbf16d Compare February 28, 2025 04:23
@alice-i-cecile alice-i-cecile added this to the 0.16 milestone Feb 28, 2025
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-ECS Entities, components, systems, and events D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 28, 2025
}

fn remove(&mut self, entity: Entity) {
if *self == entity {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definitely feels sus. What if we impl'ed this for Option<Entity> instead?

Copy link
Contributor Author

@dmyyy dmyyy Feb 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it that way at first. It felt weird to me that it's expressable for the RelationshipTarget to be None while the Relationship still points to that entity. To be fair - manually changing the RelationshipTarget to None is just as weird as setting the RelationshipTarget to some random entity (we mess up the relationship).

This felt like the more minimal change that preserves symmetry (but I'm open to changing my mind)

@alice-i-cecile alice-i-cecile removed this from the 0.16 milestone Feb 28, 2025
@dmyyy dmyyy changed the title Implement RelationshipSourceCollection for Entity One-to-One Relationships Mar 1, 2025
Copy link
Contributor

@Carter0 Carter0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it! Though I like the Option idea more personally

Copy link
Contributor

@ItsDoot ItsDoot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. FWIW, I prefer the Entity approach because it better matches how its interacted with; assuming all invariants are upheld, users will always have access to a single valid entity.

@dmyyy
Copy link
Contributor Author

dmyyy commented Mar 3, 2025

The Option<Entity> approach feels like a leaky abstraction - if I'm trying to make a one-to-one relationship I wouldn't be able to guess that I need to write it like this without looking through the source code which is a bit of a red flag IMO.

#[derive(Component)]
#[relationship(relationship_target = Below)]
pub struct Above(Entity);

#[derive(Component)]
#[relationship_target(relationship = Above)]
pub struct Below(Option<Entity>);

@alice-i-cecile Is it possible for this to be considered for 0.16?

@Carter0
Copy link
Contributor

Carter0 commented Mar 3, 2025

Yeah I see what y'all mean. There should always be a 1-1 relationship between the two entities as an invariant.

Not something to consider for this PR perhaps, but I wonder if this is a code smell then. It sorta weird to use the word "collection" in the code when really it's just one item.

@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Mar 3, 2025
@alice-i-cecile
Copy link
Member

Yep, I'll make the call today in my merge train :) The 0.16 milestone isn't exhaustive: it just captures "stuff that I would consider blocking the release for".

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Mar 4, 2025
@alice-i-cecile
Copy link
Member

The Option<Entity> approach feels like a leaky abstraction - if I'm trying to make a one-to-one relationship I wouldn't be able to guess that I need to write it like this without looking through the source code which is a bit of a red flag IMO.

#[derive(Component)]
#[relationship(relationship_target = Below)]
pub struct Above(Entity);

#[derive(Component)]
#[relationship_target(relationship = Above)]
pub struct Below(Option<Entity>);

This comment convinced me. Merging.

Merged via the queue into bevyengine:main with commit 7a1972e Mar 4, 2025
31 checks passed
github-merge-queue bot pushed a commit that referenced this pull request Apr 15, 2025
# Objective

One to one relationships (added in
#18087) can currently easily be
invalidated by having two entities relate to the same target.

Alternative to #18817 (removing one-to-one relationships)

## Solution

Panic if a RelationshipTarget is already targeted. Thanks @urben1680 for
the idea!

---------

Co-authored-by: François Mockers <[email protected]>
mockersf added a commit that referenced this pull request Apr 15, 2025
# Objective

One to one relationships (added in
#18087) can currently easily be
invalidated by having two entities relate to the same target.

Alternative to #18817 (removing one-to-one relationships)

## Solution

Panic if a RelationshipTarget is already targeted. Thanks @urben1680 for
the idea!

---------

Co-authored-by: François Mockers <[email protected]>
jf908 pushed a commit to jf908/bevy that referenced this pull request May 12, 2025
# Objective

One to one relationships (added in
bevyengine#18087) can currently easily be
invalidated by having two entities relate to the same target.

Alternative to bevyengine#18817 (removing one-to-one relationships)

## Solution

Panic if a RelationshipTarget is already targeted. Thanks @urben1680 for
the idea!

---------

Co-authored-by: François Mockers <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants