Skip to content

Conversation

@mrchantey
Copy link
Contributor

Objective

Closes #18522

This pr allows entities to have, erm, self-relations..

By default pointing a relationship to its own entity will log a warning and remove the component. However, self-referential relationships are semantically valid in many cases: Likes(self), EmployedBy(self), TalkingTo(self), Healing(self).

Solution

  • Added const ALLOW_SELF:bool = false to the Relationship trait,
  • Updated section that disallows self-relations to check for this
  • Added the allow_self flag to the macro
#[derive(Component)]
#[relationship(relationship_target = PeopleILike, allow_self)]
pub struct LikedBy(pub Entity);

#[derive(Component)]
#[relationship_target(relationship = LikedBy)]
pub struct PeopleILike(Vec<Entity>);

let entity = world.spawn_empty().id();
world.entity_mut(entity).insert(LikedBy(entity));

// The relationship is preserved
assert!(world.entity(entity).contains::<LikedBy>());
assert!(world.entity(entity).contains::<PeopleILike>());

Testing

  • added insert/remove tests

Showcase

Relationships can now optionally point to their own entity by setting #[relationship(allow_self)].

By default pointing a relationship to its own entity will log a warning and remove the component. However, self-referential relationships are semantically valid in many cases: Likes(self), EmployedBy(self), TalkingTo(self), Healing(self), and many more.

Click to view usage

To allow a relationship to point to its own entity, add the allow_self attribute:

#[derive(Component)]
#[relationship(relationship_target = PeopleILike, allow_self)]
pub struct LikedBy(pub Entity);

#[derive(Component)]
#[relationship_target(relationship = LikedBy)]
pub struct PeopleILike(Vec<Entity>);

Now entities can have relationships that point to themselves:

let entity = world.spawn_empty().id();
world.entity_mut(entity).insert(LikedBy(entity));

// The relationship is preserved
assert!(world.entity(entity).contains::<LikedBy>());
assert!(world.entity(entity).contains::<PeopleILike>());

Copilot AI review requested due to automatic review settings December 25, 2025 21:11
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enables entities to have self-referential relationships by adding an optional allow_self attribute to the #[relationship] macro. By default, relationships pointing to their own entity are rejected with a warning, but this can now be explicitly allowed for semantically valid use cases like Likes(self), EmployedBy(self), or Healing(self).

Key changes:

  • Added ALLOW_SELF: bool = false constant to the Relationship trait with appropriate documentation warnings about infinite loops
  • Extended the macro parser to accept the allow_self attribute alongside relationship_target
  • Added comprehensive tests covering insertion and removal of self-referential relationships

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
release-content/release-notes/allow_self_relationships.md Release notes documenting the new allow_self feature with usage examples
crates/bevy_ecs/src/relationship/mod.rs Added ALLOW_SELF constant to trait, updated validation logic to check the flag, added documentation and tests
crates/bevy_ecs/macros/src/lib.rs Added documentation examples for allow_self attribute and fixed existing typo in relationship_target example
crates/bevy_ecs/macros/src/component.rs Extended parser to handle allow_self keyword and generate correct trait implementation

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@mrchantey mrchantey added C-Feature A new feature, making something new possible A-ECS Entities, components, systems, and events M-Release-Note Work that should be called out in the blog due to impact X-Contentious There are nontrivial implications that should be thought through labels Dec 25, 2025
@mrchantey
Copy link
Contributor Author

apologies for the copilot noise, didnt realize this auto-review thing was on.

@hukasu
Copy link
Contributor

hukasu commented Dec 25, 2025

I feel allow_self is not descriptive enough, so I would bike shed to have the attribute to be a bit more descriptive

@mrchantey
Copy link
Contributor Author

how about allow_target_self

@Bleachfuel
Copy link
Contributor

maybe allow_self_referential

Copy link
Member

@janhohenheim janhohenheim left a comment

Choose a reason for hiding this comment

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

Some minor notes, but nothing blocking :) I personally would prefer keeping the short and sweet allow_self, but allow_self_referential is also fine.

@janhohenheim janhohenheim added the S-Needs-Review Needs reviewer attention (from anyone!) to move forward label Dec 26, 2025
@janhohenheim janhohenheim added this to the 0.19 milestone Dec 26, 2025
@janhohenheim janhohenheim added the D-Straightforward Simple bug fixes and API improvements, docs, test and examples label Dec 26, 2025
///
/// When `ALLOW_SELF` is `true`, be careful when using recursive traversal methods
/// like `iter_ancestors` or `root_ancestor`, as they may loop infinitely if an entity
/// like `iter_ancestors` or `root_ancestor`, as they will loop infinitely if an entity
Copy link
Contributor

Choose a reason for hiding this comment

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

I was thinking, could it be changed to be Relationship<const Allow_Self: bool> so that Traversal can check for Relationship<false>

Copy link
Contributor

Choose a reason for hiding this comment

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

No, wait, you should still be able to create traversal on self referential

Copy link
Contributor

@ickshonpe ickshonpe left a comment

Choose a reason for hiding this comment

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

This is a definitely a really useful feature, but the allow_self name feels potentially confusing to me. Even though allow_self has obviously nothing to do with self parameters, they are so ubiquitous in Rust, I think it would be a struggle to disassociate the two things.

Maybe reflexive would be better. It's a bit more mathy but the word precisely means something that is self referential.

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 M-Release-Note Work that should be called out in the blog due to impact S-Needs-Review Needs reviewer attention (from anyone!) to move forward X-Contentious There are nontrivial implications that should be thought through

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow relationships to point to their own entity

5 participants