-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
make the propagation logic generic #5673
Conversation
I mark this PR as draft until questions to resolve are resolved. |
Ah, yeah. Apologies I was expecting the links to be highlighted in blue, so scanned for that. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this approach a lot better than the previous PRs. Feels a lot more natural to express the relationship in this way.
's, | ||
(&'a Children, Changed<Children>), | ||
(With<Parent>, With<<T as Propagatable>::Computed>), | ||
>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These type aliases are beautiful
Possible implementation to control propagation behaviourDisclaimer: I may be over thinking 😅 POC : What's different from the current implementation ?The current implementation use a const boolean to switch from one behaviour to the other but queries are the same and request for types that may not be used (e.g. With this implementation, the behaviour is more flexible : control over the queries and the code. Why not having a system per behaviour ? Implementation// Trait to define the behaviour
trait PropagationKind {
type RootQuery<'w, 's, 'a, T>;
type LocalQuery<'w, 's, 'a, T>;
type ChildrenQuery<'w, 's, 'a, T>;
fn propagate<'w, 's, 'a, T>(
root_query: Self::RootQuery<'w, 's, 'a, T>,
local_query: Self::LocalQuery<'w, 's, 'a, T>,
children_query: Self::ChildrenQuery<'w, 's, 'a, T>,
);
}
// Possible behaviour
struct AlwaysPropagate;
struct PropagateIfChanged;
impl PropagateKind for PropagateIfChanged {
type RootQuery<'w, 's, 'a, T> = Query<
'w,
's,
(
Option<(&'static Children, Changed<Children>)>,
&'static T,
Changed<T>,
&'static mut T::Computed,
Entity,
),
Without<Parent>,
>;
type LocalQuery<'w, 's, 'a, T> = Query<
'w,
's,
(
&'a T,
Changed<T>,
&'a mut <T as Propagate>::Computed,
&'a Parent,
),
>;
type ChildrenQuery<'w, 's, 'a, T> = Query<
'w,
's,
(&'a Children, Changed<Children>),
(With<Parent>, With<<T as Propagate>::Computed>),
>;
fn propagate<'w, 's, 'a, T>(
mut root_query: Self::RootQuery<'w, 's, 'a, T>,
mut local_query: Self::LocalQuery<'w, 's, 'a, T>,
children_query: Self::ChildrenQuery<'w, 's, 'a, T>,
) {
// we use the queries here and perform the propagation.
}
}
pub trait Propagate: Component {
type Computed: Component;
type Payload;
// The kind is defined by this type.
type Kind: PropagateKind;
fn compute_root(computed: &mut Self::Computed, local: &Self);
fn compute(computed: &mut Self::Computed, payload: &Self::Payload, local: &Self);
fn payload(computed: &Self::Computed) -> Self::Payload;
}
pub fn propagate_system<'w, 's, 'a, T: Propagate>(
root_query: <T::Kind as PropagateKind>::RootQuery<'w, 's, 'a, T>,
local_query: <T::Kind as PropagateKind>::LocalQuery<'w, 's, 'a, T>,
children_query: <T::Kind as PropagateKind>::ChildrenQuery<'w, 's, 'a, T>,
) {
T::Kind::propagate(root_query, local_query, children_query);
} Usageimpl Propagate for Transform {
type Computed = GlobalTransform;
type Payload = GlobalTransform;
type Kind = PropagateIfChanged;
/* ... */
} |
Would it be doable to have a impl Propagate for Transform {
type Filter = Changed<Self>;
...
} impl Propagate for Visibility {
type Filter = AlwaysTrue;
...
} |
Yes, it's doable but AFAIK there is no static way to prevent impl Propagate for Foo {
type Filter = Changed<Goo>;
...
} |
Not that it's up to me, but that should be acceptable IMO. If you implement it incorrectly, it'll lead to incorrect behavior. As long as it doesn't cause UB, that's fine. |
If the doc is clear enough, I think it's acceptable. |
pub fn transform_propagate_system( | ||
use crate::{Children, Parent}; | ||
|
||
/// Marks a component as propagatable thrown hierachy alike `Transform`/`GlobalTransorm` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Marks a component as propagatable thrown hierachy alike `Transform`/`GlobalTransorm` | |
/// Marks a component as propagatable through hierarchy similar to `Transform`/`GlobalTransform` |
@tguichaoua I'd like to try and move forward with this, are you around to rebase and work on this? No worries if not, we'll have someone else tackle it and keep your credit. |
@alice-i-cecile I'm sorry, I'm not available to work on this. |
I am willing to adopt this, unless @Aceeri would rather. |
I'm not sure there was a consensus on which way forward to go between this, #5507 and #4216. Also, the propagations don't follow the same logic anymore as transform is now done in parallel and visibility is not. Does it make sense to parallelise visibility too? I'm not sure, it would have to be benchmarked. |
There was a discussion about this on discord, linking for posterity: https://discordapp.com/channels/691052431525675048/692572690833473578/1063191826594549760
|
Feel free if you'd like, I just wanted to get this stuff in for some future work related to splitting hierarchies |
@Aceeri could you describe in a new issue those future works? Without more details I would be reluctant to make it generic now that we have only two cases and they are different... |
Ya, will do so early tomorrow, the gist of it is that I'd like a way to opt out of these hierarchies but keep the organization of them. Since for example I would like the arms of my player to still be "children" of the player, but I don't want them to sync to the transform since that will override the physics joints doing their thing. So I was thinking something along the lines of An alternative here would be to have propagation logic be opt in and just have the |
Backlog cleanup: lack of activity (although attempted adoption last year) and |
Objective
Bevy now has two component pairs that are propagated through the hierarchy (
Transform
/GlobalTransform
andVisibility
/ComputedVisibility
).The objective of this PR is to create a generic system that performs the propagation logic to avoid to write boilerplate code.
Previous PR
This has already been proposed in #5507 and #4216.
What's different ?
Transform
) instead of the computed one that is generaly a prefixed or a suffixed version of the main type (e.g.GlobalTransform
).ComputedVisibility
that setsis_visible_in_view
tofalse
.Solution
This is achieved with the
Propagate
trait and a generic systempropagate_system<T: Propagate>
inbevy_hierarchy
. This trait allow to customize how the propagation is performed.The
Propagate
trait is implemented on the local component (see vocabulary section) and defines these methods:compute_root
to update the computed component of the root entity from it's local one.compute_root
to update the computed component from it's local one and the payload received from it's parent.payload
to compute the payload to pass to children from it's computed component.The propagation system has two possible behaviours:
Visibility
/ComputedVisibility
).Transform
/GlobalTransform
).The choice of the behaviour can be implemented in two ways:
Propagate
trait (current implemetation)propagate_is_changed_system
andalways_propagate_system
.Vocabulary
Questions to resolve
Propagate
trait or by using two different systemspropagate_is_changed_system
andalways_propagate_system
?Changelog
Propagate
trait.propagate_system
.transform_propagate_system
.visibility_propagate_system
(was not public).bevy_transform
tobevy_hierarchy
.Migration Guide
transform_propagate_system
has been removed.propagate_system
andPropagate
to create propagable component.