Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement insert and remove reflected entity commands #8895

Merged
merged 12 commits into from Aug 28, 2023

Conversation

NoahShomette
Copy link
Contributor

@NoahShomette NoahShomette commented Jun 20, 2023

Objective

To enable non exclusive system usage of reflected components and make reflection more ergonomic to use by making it more in line with standard entity commands.

Solution

  • Implements a new EntityCommands extension trait for reflection related functions in the reflect module of bevy_ecs.

  • Implements 4 new commands, insert_reflect, insert_reflect_with_registry, remove_reflect, and remove_reflect_with_registry. Both insert commands take a Box<dyn Reflect> component while the remove commands take the component type name.

  • Made EntityCommands fields pub(crate) to allow access in the reflect module. (Might be worth making these just public to enable user end custom entity commands in a different pr)

  • Added basic tests to ensure the commands are actually working.

  • Documentation of functions.


Changelog

Added:

  • Implements 4 new commands on the new entity commands extension.
  • insert_reflect
  • remove_reflect
  • insert_reflect_with_registry
  • remove_reflect_with_registry

The commands operate the same except the with_registry commands take a generic parameter for a resource that implements AsRef<TypeRegistry>. Otherwise the default commands use the AppTypeRegistry for reflection data.

Changed:

  • Made EntityCommands fields pub(crate) to allow access in the reflect module.

Hopefully this time it works. Please don't make me rebase again ☹

@MrGVSV MrGVSV added A-ECS Entities, components, systems, and events C-Usability A simple quality-of-life change that makes Bevy easier to use A-Reflection Runtime information about types labels Jun 20, 2023
@MrGVSV MrGVSV self-requested a review June 20, 2023 02:03
@nicopap nicopap self-requested a review June 20, 2023 04:30
Copy link
Member

@MrGVSV MrGVSV left a comment

Choose a reason for hiding this comment

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

Looking good. Along with my general nitpicks and suggestions, I left a few comments open for discussion for other reviewers.

Overall, I'm still on the fence about this change. On the one hand, it makes reflection more immediately useful to users without having to understand the complexities of ReflectComponent. On the other hand, the actual command is pretty straightforward if someone wanted to just write it themselves with a custom command or closure command (not trying to downplay this change btw, just want us to be mindful of what we put on a very core API).

It'd be nice to get some input from someone more on the ECS side of things (since for me, all the reflection stuff looks great!).

crates/bevy_reflect/src/type_registry.rs Outdated Show resolved Hide resolved
Comment on lines 5 to 8
/// An extension trait for [`EntityCommands`] for reflection related functions
pub trait EntityCommandsReflectExtension {
Copy link
Member

Choose a reason for hiding this comment

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

Discussion: This is based on my suggestion to use an extension trait in order to help create a separation from reflection-based behaviors. My original reasoning was that we don't want beginner users reaching for this option right out of the gate (especially since reflection still has some quirks that make it not very beginner friendly). And hopefully we can bring this in fully once reflection/scenes are a little more fleshed out.

However,— to argue against myself for a moment,— it's a seemingly "unnecessary" separation from a user perspective, especially since it requires a completely separate import. On top of this, it makes finding this functionality much more difficult for users who do need it.

I'd like to hear feedback from others (including you, @NoahShomette haha) on opinions here. Should we just make these proper methods on EntityCommands?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the separation makes logical sense and I do like it being separated because at least from a code perspective it keeps all the more special purpose reflection functions away from the general functions which should be much more commonly used. However it could go either way and I don't really have a strong opinion on it. I do think if we added more functions then the division might get more useful just from a code base perspective since the actual EntityCommands file is getting rather big already. It also depends on how "public" reflection related things are supposed to be which I don't have a great gauge on so I'll defer to others on that point.

Additionally I know at least for me I use an IDE and I very rarely purposefully import things. I might be an outlier but I would assume most people use something that will autocomplete and suggest related functions even if they aren't already imported which would make the discoverability point much less damning.

I'd overall be in favor of keeping the extension trait.

crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
@NoahShomette
Copy link
Contributor Author

Looking good. Along with my general nitpicks and suggestions, I left a few comments open for discussion for other reviewers.

Overall, I'm still on the fence about this change. On the one hand, it makes reflection more immediately useful to users without having to understand the complexities of ReflectComponent. On the other hand, the actual command is pretty straightforward if someone wanted to just write it themselves with a custom command or closure command (not trying to downplay this change btw, just want us to be mindful of what we put on a very core API).

It'd be nice to get some input from someone more on the ECS side of things (since for me, all the reflection stuff looks great!).

I definitely agree its a small change and easily implemented by the end user (although EntityCommands needs public fields for that technically first), however it was a bit disconcerting to me that there wasn't any way to deferred insert reflect components when I ran into it. I think Bevy focuses enough on this and its a big part of end user actions, specifically interacting with commands and thinking deferred and parallel, that it makes sense to me to have first party support for this kind of thing. Its a little thing but it helps to make reflect more usable and more in line with the rest of the engine imo.

github-merge-queue bot pushed a commit that referenced this pull request Jun 21, 2023
# Objective

- Use `AppTypeRegistry` on API defined in `bevy_ecs`
(#8895 (comment))

A lot of the API on `Reflect` depends on a registry. When it comes to
the ECS. We should use `AppTypeRegistry` in the general case.

This is however impossible in `bevy_ecs`, since `AppTypeRegistry` is
defined in `bevy_app`.

## Solution

- Move `AppTypeRegistry` resource definition from `bevy_app` to
`bevy_ecs`
- Still add the resource in the `App` plugin, since bevy_ecs itself
doesn't know of plugins

Note that `bevy_ecs` is a dependency of `bevy_app`, so nothing
revolutionary happens.

## Alternative

- Define the API as a trait in `bevy_app` over `bevy_ecs`. (though this
prevents us from using bevy_ecs internals)
- Do not rely on `AppTypeRegistry` for the API in question, requring
users to extract themselves the resource and pass it to the API methods.

---

## Changelog

- Moved `AppTypeRegistry` resource definition from `bevy_app` to
`bevy_ecs`

## Migration Guide

- If you were **not** using a `prelude::*` to import `AppTypeRegistry`,
you should update your imports:

```diff
- use bevy::app::AppTypeRegistry;
+ use bevy::ecs::reflect::AppTypeRegistry
```
@nicopap
Copy link
Contributor

nicopap commented Jun 23, 2023

With #8901, it's now possible to use AppTypeRegistry in bevy_ecs. I think it might make some of the implementation simpler.

@nicopap
Copy link
Contributor

nicopap commented Jul 9, 2023

FYI if you want this to go forward, you need to address the comments reviewers made.

@NoahShomette
Copy link
Contributor Author

NoahShomette commented Jul 12, 2023

Apologies for the absolutely horrible PR timeline now, but I think it should be fixed from a commit point of view and all of the conversations should be resolved.

I added additional insert_reflected_with_registry and remove_reflected_with_registry commands as well and made the standard commands insert_reflected and remove_reflected use the AppTypeRegistry for their reflection data.

Also apologies for the delay in updating this but I fell ill and just got super busy :(

@NoahShomette
Copy link
Contributor Author

NoahShomette commented Jul 12, 2023

I'm not sure what the standard is for commands, but would something like this be possible for maximum flexibility?

We do have some operations in the actual command call but it allows any TypeRegistry to be used rather than just resources and it only involves cloning a ReflectComponent (Which I dont believe would be a huge problem)

    fn remove_reflected_with_registry(
        &mut self,
        component_type_name: String,
       type_registry: &TypeRegistry
    ) -> &mut Self {
       let type_info = self.component.type_name();
       let Some(type_registration) = registry.read().get_with_name(type_info) else {
                panic!("Could not get type registration (for component type {}) because it doesn't exist in the TypeRegistry.", component.type_name());
            }
      let Some(reflect_component) = type_registration.data::<ReflectComponent>() else {
                    panic!("Could not get ReflectComponent data (for component type {}) because it doesn't exist in this TypeRegistration.", component.type_name());
                }

        self.commands.add(RemoveReflectedWithRegistry {
            entity: self.entity,
            reflect_component: reflect_component.clone(),
        });
        self
    }

Copy link
Contributor

@nicopap nicopap 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 the first half of my review. I'm giving feedback on the actual code next.

crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
/// }
///
/// ```
fn remove_reflected(&mut self, component_type_name: String) -> &mut Self;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest using a impl Into<Cow<'static, str>> here instead of String so that it's possible to use the API without allocation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added this, I believe I put it in correctly but I would appreciate a double check as I wasn't able to get it to work without having to call .to_owned() when passing stuff into the function and I'm not sure if thats an issue with it now. I was getting lifetime bounds errors which you can replicate by just removing the .to_owned() from the tests

crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
@nicopap nicopap self-requested a review August 17, 2023 06:19
@nicopap nicopap added this to the 0.12 milestone Aug 17, 2023
Copy link
Contributor

@nicopap nicopap left a comment

Choose a reason for hiding this comment

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

Looks excellent! I'd require just some minor adjustments.

crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
@NoahShomette
Copy link
Contributor Author

Looks excellent! I'd require just some minor adjustments.

Awesome thank you so much! I implemented all your feedback so it should be good to go from that regards!

@github-actions
Copy link
Contributor

Example alien_cake_addict failed to run, please try running it locally and check the result.

Copy link
Contributor

@nicopap nicopap left a comment

Choose a reason for hiding this comment

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

Great job! LGTM

Comment on lines 254 to 256
return;

};
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return;
};
return;
};

Comment on lines 258 to 260
return;

};
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return;
};
return;
};

crates/bevy_ecs/src/reflect/entity_commands.rs Outdated Show resolved Hide resolved
@nicopap
Copy link
Contributor

nicopap commented Aug 17, 2023

Just don't worry about CI, it's broken. Also don't worry about formatting within let else it's also broken, but both are going to get fixed soon(-ish)!

@NoahShomette
Copy link
Contributor Author

Just don't worry about CI, it's broken. Also don't worry about formatting within let else it's also broken, but both are going to get fixed soon(-ish)!

Haha that works for me! Thank you very much for reviewing and helping me out!

@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Aug 20, 2023
@NoahShomette
Copy link
Contributor Author

I realized that the two with_registry commands were removing the registry resource but were not returning it afterwards. Updated both functions to use a resource_scope so that should be fixed now.

@alice-i-cecile
Copy link
Member

@NoahShomette this needs to be formatted, but once that's done I'll merge it!

@NoahShomette
Copy link
Contributor Author

@NoahShomette this needs to be formatted, but once that's done I'll merge it!

Done!

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Aug 28, 2023
Merged via the queue into bevyengine:main with commit 72fc63e Aug 28, 2023
20 checks passed
@NoahShomette NoahShomette deleted the reflect_entity_commands branch August 29, 2023 01:23
Shatur pushed a commit to projectharmonia/bevy that referenced this pull request Aug 30, 2023
# Objective

To enable non exclusive system usage of reflected components and make
reflection more ergonomic to use by making it more in line with standard
entity commands.

## Solution

- Implements a new `EntityCommands` extension trait for reflection
related functions in the reflect module of bevy_ecs.
- Implements 4 new commands, `insert_reflect`,
`insert_reflect_with_registry`, `remove_reflect`, and
`remove_reflect_with_registry`. Both insert commands take a `Box<dyn
Reflect>` component while the remove commands take the component type
name.

- Made `EntityCommands` fields pub(crate) to allow access in the reflect
module. (Might be worth making these just public to enable user end
custom entity commands in a different pr)
- Added basic tests to ensure the commands are actually working.
- Documentation of functions.

---

## Changelog

Added:
-  Implements 4 new commands on the new entity commands extension.
- `insert_reflect`
- `remove_reflect`
- `insert_reflect_with_registry`
- `remove_reflect_with_registry`

The commands operate the same except the with_registry commands take a
generic parameter for a resource that implements `AsRef<TypeRegistry>`.
Otherwise the default commands use the `AppTypeRegistry` for reflection
data.

Changed:

- Made `EntityCommands` fields pub(crate) to allow access in the reflect
module.

> Hopefully this time it works. Please don't make me rebase again ☹
@cart cart mentioned this pull request Oct 13, 2023
43 tasks
rdrpenguin04 pushed a commit to rdrpenguin04/bevy that referenced this pull request Jan 9, 2024
# Objective

To enable non exclusive system usage of reflected components and make
reflection more ergonomic to use by making it more in line with standard
entity commands.

## Solution

- Implements a new `EntityCommands` extension trait for reflection
related functions in the reflect module of bevy_ecs.
- Implements 4 new commands, `insert_reflect`,
`insert_reflect_with_registry`, `remove_reflect`, and
`remove_reflect_with_registry`. Both insert commands take a `Box<dyn
Reflect>` component while the remove commands take the component type
name.

- Made `EntityCommands` fields pub(crate) to allow access in the reflect
module. (Might be worth making these just public to enable user end
custom entity commands in a different pr)
- Added basic tests to ensure the commands are actually working.
- Documentation of functions.

---

## Changelog

Added:
-  Implements 4 new commands on the new entity commands extension.
- `insert_reflect`
- `remove_reflect`
- `insert_reflect_with_registry`
- `remove_reflect_with_registry`

The commands operate the same except the with_registry commands take a
generic parameter for a resource that implements `AsRef<TypeRegistry>`.
Otherwise the default commands use the `AppTypeRegistry` for reflection
data.

Changed:

- Made `EntityCommands` fields pub(crate) to allow access in the reflect
module.

> Hopefully this time it works. Please don't make me rebase again ☹
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 A-Reflection Runtime information about types C-Usability A simple quality-of-life change that makes Bevy easier to use S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

None yet

4 participants