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

Add UI GhostNode #15341

Merged
merged 27 commits into from
Oct 2, 2024
Merged

Add UI GhostNode #15341

merged 27 commits into from
Oct 2, 2024

Conversation

villor
Copy link
Contributor

@villor villor commented Sep 20, 2024

Objective

Solution

Add a GhostNode component to bevy_ui and update all the relevant systems to use it to traverse for UI children.

  •  ghost_hierarchy module
    • Add GhostNode
    • Add UiRootNodes system param for iterating (ghost-aware) UI root nodes
    •  Add UiChildren system param for iterating (ghost-aware) UI children
  • Update layout::ui_layout_system
    •  Use ghost-aware root nodes for camera updates
    • Update and remove children in taffy
      • Initial spawn
      •  Detect changes on nested UI children
    • Use ghost-aware children traversal in update_uinode_geometry_recursive
  • Update the rest of the UI systems to use the ghost hierarchy
    • stack::ui_stack_system
    • update::
      •  update_clipping_system
      •  update_target_camera_system
    •  accessibility::calc_name

Testing

  • Added a new example ghost_nodes that can be used as a testbed.
  •  Added unit tests for some of the traversal utilities in ghost_hierarchy
  • Ensure this fulfills the needs for currently known use cases
    • Reactivity libraries (test with bevy_reactor)
    • Text spans (mentioned by koe on discord)

Performance

See comment below

Migration guide

Any code that previously relied on Parent/Children to iterate UI children may now want to use bevy_ui::UiChildren to ensure ghost nodes are skipped, and their first descendant Nodes included.

UI root nodes may now be children of ghost nodes, which means Without<Parent> might not query all root nodes. Use bevy_ui::UiRootNodes where needed to iterate root nodes instead.

Potential future work

  • Benchmarking/optimizations of hierarchies containing lots of ghost nodes
  • Further exploration of UI hierarchies and markers for root nodes/leaf nodes to create better ergonomics for things like UiLayer (world-space ui)

@villor villor marked this pull request as draft September 20, 2024 23:47
@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-UI Graphical user interfaces, styles, layouts, and widgets M-Needs-Release-Note Work that should be called out in the blog due to impact S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Sep 20, 2024
@viridia
Copy link
Contributor

viridia commented Sep 21, 2024

I'm going to patch this into bevy_reactor and see if I can get it working.

@viridia
Copy link
Contributor

viridia commented Sep 21, 2024

OK, I managed to come up with a bare bones version of bevy_reactor that uses this, but I had to disable a ton of stuff because it's incompatible with changes in 0.15-dev (which has nothing to do with this PR).

What I am seeing is that everything looks good on the initial render; however if I replace the ghost node's children, I no longer see those children.

Unfortunately, I can't 100% guarantee that this is not a problem in my code; I can't run the EGUI world inspector in Bevy 0.15, so I have to make do with printf debugging of the entity tree. From what I can tell, Cond is doing the right thing, but I'm not 100% sure.

If you want to try it out yourself, the code is here: https://github.com/viridia/bevy_reactor - note that only the 'simple2' example compiles, everything else is broken.

@viridia
Copy link
Contributor

viridia commented Sep 21, 2024

Overall, the code looks pretty good. I see the TODO comment about the change detection, which aligns with my intuitions about the root cause of the problem I am seeing. I suspect that when my conditional node, which is a ghost node, deletes and re-creates its children, it's not triggering a layout pass on the parent of the ghost node because the change detection isn't propagating upward.

@villor
Copy link
Contributor Author

villor commented Sep 21, 2024

OK, I managed to come up with a bare bones version of bevy_reactor that uses this…

Thank you for setting this up! Very good to have a real-world scenario to test with 👍

What I am seeing is that everything looks good on the initial render; however if I replace the ghost node's children, I no longer see those children.

This is to be expected currently, as the layout system implementation does not yet do change detection on nested children.

@viridia
Copy link
Contributor

viridia commented Sep 21, 2024

OK, looks like everything in my simple example is working now - this demonstrates Cond, TextComputed and ViewTemplate. I'm going to migrate some more code to use Ghost nodes next.

@alice-i-cecile alice-i-cecile added X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes labels Sep 21, 2024
@villor
Copy link
Contributor Author

villor commented Sep 23, 2024

I'll re-post some thoughts here that I wrote on Discord:

I've been thinking a bit more about ghost nodes, and UI hierarchies in general... It seems like there are a lot more usecases than initially thought, at least partially. After reading koe's discussion thread about UiTexture, it becomes clear that UI root nodes With<Parent> are definitely useful in more cases. That proposal could also benefit from being able to mark entities that stop the UI hierarchy, not traversing further down.

So I thought, why not flip the whole thing around? Correct me if I'm wrong, but if we mark the root and the leafs of a UI hierarchy, any non-Node entities in-between could be considered ghost nodes, without having to mark them as GhostNode (a warning about missing Transform/Visibility components could be useful though). This would allow UI hierarchies to exist within 3D/2D hierarchies, and the reverse, opening up for more ergonomic ways to do world space UI and 2D/3D in UI space 🤔

@villor
Copy link
Contributor Author

villor commented Oct 1, 2024

Wanting to see how this affects the performance of current stack/layout systems (with no ghost nodes), I ran a stress test between main (f08f077) and this PR (a7decfb).

cargo run --profile stress-test --features trace_tracy --example many_buttons -- --relayout

Red is main, yellow is this PR.

ui_layout_system:
ui_layout_system

ui_stack_system:
ui_stack_system

Looks like it has a slight hit on the stack system, but maybe not significant enough to care about for now. I'll leave that up to reviewers to decide.

Performance with ghost nodes in the hierarchy can be benchmarked and optimized in a future PR. I expect it to be fairly slow with the current solution for deeply nested ghost hierarchies.

Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

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

Useful to have some benchmarks. I'm fine to merge it even with performance regressions. bevy_ui's problem is not "cannot render a billion buttons at 60 FPS", it's "we're missing the features required to build complex UI", and all indications are that this is a great step towards the latter.

Copy link
Contributor

@UkoeHB UkoeHB left a comment

Choose a reason for hiding this comment

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

Looks good, minor doc comments and one small perf request. Nice use of system params.

crates/bevy_ui/src/ghost_hierarchy.rs Outdated Show resolved Hide resolved
crates/bevy_ui/src/ghost_hierarchy.rs Outdated Show resolved Hide resolved
crates/bevy_ui/src/layout/ui_surface.rs Outdated Show resolved Hide resolved
crates/bevy_ui/src/layout/ui_surface.rs Outdated Show resolved Hide resolved
examples/ui/ghost_nodes.rs Outdated Show resolved Hide resolved
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
@villor
Copy link
Contributor Author

villor commented Oct 1, 2024

@UkoeHB Thank you for the review! 😍
I have applied the suggested doc comments. Had a question about the perf thing, see above.

@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 Oct 1, 2024
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Oct 2, 2024
Merged via the queue into bevyengine:main with commit f86ee32 Oct 2, 2024
31 checks passed
@eidloi
Copy link

eidloi commented Oct 2, 2024

Late to the party again, but I would like to point out that the majority of users would not want to pay the performance hit (over 2x!) and complexity hit (because now everybody needs to work around the possible ghost nodes) for a feature they will never use. It also splits hierarchy traversal in two distinct versions for "normal" and UI use. Bevy UI is difficult enough as-is for users.

This should be feature gated at the very least, though it still requires all UI crate makers to rewrite all their systems that rely on tree traversal. Which will be a lot.

On another note, I think mixing the "ghost" and regular UI nodes is a terrible approach as it mixes "virtual" configs with actual configs for UI, increasing complexity in both the management, extraction, and introspection side. Normally reactive DOMs are entirely separate from their render versions, much like how we have a main world and a render world in Bevy.

It would make more sense to put them in a separate subapp and sync their diff to the main world (maybe even two world so that a world-world diff pre-filter could be implemented). To reason is that the "logical" view might have no hierarchical correspondence with the rendered one. Think about re-using fragments: The logical tree would have only the fragment link in the hierarchy, while the template is elsewhere, perhaps synced on it's own.

Another reason would be that the ghost approach is not resilient against external modifications, while having only the logical tree is. While this may not seem a worry, all library makers will have a ton of issues opened 'cus someone wanted to "just update the text" or something.

@villor
Copy link
Contributor Author

villor commented Oct 2, 2024

Late to the party again, but I would like to point out that the majority of users would not want to pay the performance hit (over 2x!)

I agree that the performance hit is a bit much at its current state. But I'm confident this can be optimized so that there is no significant performance hit.

and complexity hit (because now everybody needs to work around the possible ghost nodes) for a feature they will never use. It also splits hierarchy traversal in two distinct versions for "normal" and UI use. Bevy UI is difficult enough as-is for users.

For someone who doesn't use ghost nodes this PR will not change anything. If you don't care about ghost nodes, you can continue using Parent/Child. The migration guide is more aimed at library authors who might want to ensure their functionality still works with ghost nodes in the hierarchy.

However, I do agree that this is not the most optimal approach. There is still design work to be done to reach a nice UI hierarchy abstraction that fits all use cases while also being easy to grasp and use. We have had some discussions about this on Discord. But a GitHub discussion for this would be good so we can all reach a consensus on the right path.

On another note, I think mixing the "ghost" and regular UI nodes is a terrible approach as it mixes "virtual" configs with actual configs for UI, increasing complexity in both the management, extraction, and introspection side. Normally reactive DOMs are entirely separate from their render versions, much like how we have a main world and a render world in Bevy.
...

To me ghost nodes are part of the interface here (just like Mesh and Material are interfaces to the separate render hierarchy), something to use not just for reactive libraries, but other use cases as well. While I could see a separate retained hierarchy for the UI nodes kept as an optimization (along with a well documented interface to query it), I think the main ECS hierarchy should allow mixing UI and non UI entities within the hierarchy, as well as starting new UI hierarchies and terminating them, allowing more ergonomic world space UI and UI space 2D/3D entities.

@eidloi
Copy link

eidloi commented Oct 2, 2024

For someone who doesn't use ghost nodes this PR will not change anything. If you don't care about ghost nodes, you can continue using Parent/Child. The migration guide is more aimed at library authors who might want to ensure their functionality still works with ghost nodes in the hierarchy.

But this is the problem. All library authors must make sure they support the ghost nodes since they cannot be sure users won't use their widgets in ghost contexts, while all users must make sure they consider them since libraries may use it beyond just supporting it. And I am saying this as a library author, spending weeks on night shift refactoring just to support 3 ppl makes me want to stop entirely.

To me ghost nodes are part of the interface here (just like Mesh and Material are interfaces to the separate render hierarchy)

Except that they are not components that sit on their target and do something in a different world, which makes them no longer be "configs".

Anyway I am just a user not a maintainer so I leave it to them, but I doubt this will bring any benefit for the masses (but will bring a lot of headaches).

@viridia
Copy link
Contributor

viridia commented Oct 2, 2024

Normally reactive DOMs are entirely separate from their render versions, much like how we have a main world and a render world in Bevy.

I have implemented both approaches now (reactive nodes as a separate tree, and combined in the same tree). I can report that using a single tree resulted in a huge reduction in overall complexity of the ui library code.

This doc describes in detail my experiences migrating my UI framework to ghost nodes.

Normal Bevy users may not ever use ghost nodes, but I suspect that a number of popular crates will incorporate them. There is a very good chance that BSN is going to incorporate reactivity using ghost nodes, so putting it behind a feature flag would require putting BSN behind a feature flag, which I don't think is going to happen.

@cart
Copy link
Member

cart commented Oct 2, 2024

I'm in the process of reviewing @viridia's reactive system (based on ghost nodes). I don't want to make a final call on this until I know my feelings about that impl and how it uses ghost nodes.

Storing this data "in the main world" and attaching it directly to entities has really driven down complexity in bevy_reactor. I've been really stoked on what I've seen so far (and how nicely it appears to fit into the BSN model). I want to give this a fair shake. If we find pain points in the impl that feel like deal breakers, or the value doesn't seem to outweigh the added complexity, we can revert this.

Given that 3rd party library authors can choose to ignore supporting ghost nodes (ex: to my knowledge Sickle UI would have continued working as-is without ghost nodes, other than potentially behaving unexpectedly if a user tries to use them), I don't see the big deal here, especially in the short term while we're evaluating.

I do consider this to still be an experiment. Doing it in-tree made @viridia's life easier. I think in general 3rd party UI authors should just ignore it for now while we evaluate, unless they also want to experiment.

If supporting GhostNodes isn't currently opt-in at the moment for 3rd party devs, please say so and we can try to sort something out.

@eidloi
Copy link

eidloi commented Oct 3, 2024

Given that 3rd party library authors can choose to ignore supporting ghost nodes (ex: to my knowledge Sickle UI would have continued working as-is without ghost nodes, other than potentially behaving unexpectedly if a user tries to use them), I don't see the big deal here, especially in the short term while we're evaluating.

But I do. I am not going to claim the crate works with vanilla Bevy if I know full well the moment someone tries to use a BSN it will blow up. And why wouldn't they want to use a BSN the moment it lands? Do you expect me to patch it for the next release knowing it will be obsolete in a month?

I am eager to see how you would implement docking zones, tabs that can be torn out to floating panels, floating panels with docking zones that you can dock in another docking zone, docking zone splits, etc.
Hint: You won't. And as far as I have seen it isn't even planned for the Bevy editor nor have I seen it in Quill.

I am also eager to see how you would support arbitrary adding, removing, or reordering children across an unknown number of ghost nodes. Hint: You won't. Ghost nodes implicitly remove support for manipulating regular nodes directly. As such everyone is forced to wrap every tiny thing in a ghost node and manipulate the ghost tree as is, going the full circle just with compound complexity. You also loose direct access to measurements on these ghost nodes, so every time you change the ghost tree, a regular parent lookup becomes necessary if you care about scaling things down the tree (like you would if you add / remove a bunch of children that are dynamically scaled). A frame delayed at that.

Text and 3D will have the same issues once people start trying to use it.

There are more reasons listed in the discord but I understand the community agrees with this so I will stop at this post.

As for sickle_ui, it would need to be re-implemented from the ground up based on BSN (which doesn't exist yet), but again I don't see how the critical features would be even doable, let alone when I would do it. I simply lost another year developing the crate and it was nearing parity with egui+egui dock together, not that it matters when it was undesirable. True, reactivity is missing and was never planned due to my experience with anything "reactive". Development for an alternative solution was underway since Monday (the first time I could actually start working on our game) but now I have to go back to the drawing board. I am eager to see what alternatives Bevy will provide and most of all when (though I will probably not be around by then).

As a closing thought: I doubt you'll get feedback from 3rd party crate authors since Quill is already on board even though it worked without, and sickle is out since it cannot work within. There are no others, or at least not deep enough to mind.

@viridia
Copy link
Contributor

viridia commented Oct 3, 2024

I'm not ready to respond to each of your individual points, although I am interested in the answers and the objections you raise. However, I do want to clarify some things, just to insure that we're not arguing past one another:

First, while Quill does not currently use ghost nodes, but it might in the future - Quill currently has a number of subtle footguns which ghost nodes may or may not solve. Right now ghost nodes are used in bevy_reactor, a framework which might have resembled Quill at one point but has diverged greatly since then. bevy_reactor incorporates a number of ideas from sickle_ui, and in general provides an API which is much closer to vanilla Bevy than Quill's system of Xilem-like views.

Fine-grained systems like bevy_reactor tend to have a large number of micro-reactions, and managing these as a separate tree creates a lot of complexity as well as issues around closure lifetimes and variable capture. (Credit where credit is due: it was the comment by Sander on the BSN proposal that got me interested in working towards a single-tree solution.)

The BSN documents have stated from the beginning that reactivity would be a part of the solution, but not a lot of details were given. Part of the motivation for bevy_reactor was to try and do experiments to fill in those missing gaps. But these were always intended to be experiments, I never pushed a crate and never tried to get a user base or persuade people to use it.

What this means is that frameworks that want to interoperate with BSN were always going to have to accommodate reactivity in some form; the only alternative would be to lobby to drop the reactivity requirement, which means coming up with a convincing and viable alternative strategy. The good news (for you) is that you are one of the few people who can make such an argument and be taken seriously, because you have a framework that operates at scale, which most UI frameworks don't. (Vanilla bevy_ui doesn't operate at scale: while it's easy to spawn a complex UI, keeping it up to date and dynamic quickly bogs down into a morass of complexity. But a lot of people seem to think that building a better UI toolkit is about making spawning easier, when spawning is not the problem.)

I always thought that there would be room for multiple UI frameworks with different APIs and different authors, because the choice of UI framework is a personal decision that involves aesthetic as well as technical considerations. But I think that it's important that these frameworks are able to co-exist at some level. At the very least, one can imagine an app that is based on sickle_ui, but uses a plugin world inspector popup that is implemented in BSN. Or perhaps the other way around.

The other thing I would say is that so far, I have found working with ghost nodes to be pretty painless, however that may be because I rely entirely on bevy_ui for all layout calculations (well, except for floating popups), and ghost nodes only impact layout - in every other respect they are like normal nodes. I suppose someone who was doing their own layout traversal might have problems; but I think that can be solved.

@cart
Copy link
Member

cart commented Oct 3, 2024

@eidloi

But I do. I am not going to claim the crate works with vanilla Bevy if I know full well the moment someone tries to use a BSN it will blow up. And why wouldn't they want to use a BSN the moment it lands? Do you expect me to patch it for the next release knowing it will be obsolete in a month?

I expect nothing from you and I would like to support what you're doing in any way that I can, while still making forward progress on upstream Bevy UI / Scene improvements.

I am eager to see how you would implement docking zones, tabs that can be torn out to floating panels, floating panels with docking zones that you can dock in another docking zone, docking zone splits, etc.
Hint: You won't. And as far as I have seen it isn't even planned for the Bevy editor nor have I seen it in Quill.
I am also eager to see how you would support arbitrary adding, removing, or reordering children across an unknown number of ghost nodes. Hint: You won't.

From my perspective we are still in the process of exploring and evaluating the bounds of what is possible with ghost nodes. I'm just this week diving back in to this space after sadly being sidetracked for awhile working on other things. It is very possible that your assessment of the situation is correct. I just sadly haven't fully wrapped my head around the space yet enough to convince myself that these scenarios aren't possible.

I own (and apologize for) the fact that this probably should not have been merged in its current form, especially without more messaging around the state of the effort, our expectations around it, and strong urgings for people to not adopt it yet. I'm sorry that this came out of nowhere, I'm sorry this has derailed your work, and I'm sorry you feel pressured to drop everything and support it.

There are more reasons listed in the discord but I understand the community agrees with this so I will stop at this post.

I'm not sure we have consensus on "ghost nodes" as a foundational UI piece yet. Needs more investigation / proof-of-viability first.

As for sickle_ui, it would need to be re-implemented from the ground up based on BSN (which doesn't exist yet), but again I don't see how the critical features would be even doable, let alone when I would do it. I simply lost another year developing the crate and it was nearing parity with egui+egui dock together, not that it matters when it was undesirable. True, reactivity is missing and was never planned due to my experience with anything "reactive". Development for an alternative solution was underway since Monday (the first time I could actually start working on our game) but now I have to go back to the drawing board. I am eager to see what alternatives Bevy will provide and most of all when (though I will probably not be around by then).

If anything we build erases the work you've done over the past year, thats worth discussing. I can't promise we won't break you (or other 3rd party Bevy UI frameworks), but as much as possible I would like to ensure there are easy paths to bring things forward.

not that it matters when it was undesirable

First: the value and desirability of your work is clear. That being said, given the-in-flux state of "upstream Bevy UI" and the promise (for years) that things would change, I hope it isn't too surprising that the things being built on the framework as it exists today may need to rethink some of their assumptions if they want to work in the new system.

As a closing thought: I doubt you'll get feedback from 3rd party crate authors since Quill is already on board even though it worked without, and sickle is out since it cannot work within. There are no others, or at least not deep enough to mind.

Yup this makes sense to me.

@UkoeHB
Copy link
Contributor

UkoeHB commented Oct 3, 2024

The main alternative to GhostNode that's entered discussion is these discord comments: outline 1 and outline 2. @viridia has also suggested using an Owned/Owner relationship instead of Parent/Children.

The over-arching use cases for this hierarchy complexity are:

  • 'Accessory entities' like text spans, entity-scoped-observers, and bevy_reactor control nodes need be cleaned up by despawn_recursive on their owners/context.
  • 'Accessory entities' need direct access to associated context (such as ComputedTextBlock in text blocks).
  • Accessory entities may be interspersed with each each other. For example embedded UI inside a text block (there are no concrete ideas how to solve this yet AFAIK).
  • Preparation for world-space UI where you want a UI hierarchy to be affected by Transform/Visibility of the owning 2d/3d hierarchy. And also world-space-in-UI(-in-worldspace), essentially multiple layers of back-and-forth.

A single complex hierarchy is one solution to the above problems but another approach may also work.

@viridia
Copy link
Contributor

viridia commented Oct 4, 2024

To be clear: I suggested using Owner/Owned only for cases where the ghost nodes are leaves, not in cases where they are interior nodes. Owner/Owned does not solve the latter use case.

One might ask: why use ghost nodes on leaves in the first place?

First, some context: a significant overall trend in Bevy development can be summed up as "...as entities". That is, we are increasingly moving towards a world in which visible "nodes" have a halo of associated, invisible satellite entities, for a variety of housekeeping purposes: observation, callbacks, state management and many others.

Unfortunately, the bevy_ui layout framework complains about these entities being in-tree unless steps are taken to filter them out of the traversal. Ghost nodes are a convenient hammer for eliding these entities and avoiding the warning: in fact, in my own experiments, I'd say about 2/3 of all ghost nodes have no children.

But ghost nodes aren't the only way to do this, and not necessarily the most efficient. The layout system still has to iterate over these entities, even if they are ignored. And unfortunately, ghost nodes also incur the overhead of traversing into an (empty) child tree.

Using a separate relationship for satellite leaf nodes, such as Owner/Owned, in parallel with Parent/Child, would solve the use case in a more efficient way, because the layout system would never see the satellite entities at all.

Ghost nodes still have value for their primary use case, which is acting as a proxy/placeholder for dynamically-generated children. (In fact, I realized just now that "ProxyNode" would also have been a valid name). As stated above, I have explored many permutations of this, including parallel trees, storing the data in components, and so on. The ghost node solution is the simplest and cleanest approach I have been able to come up with. That doesn't mean it's the best solution possible :)

In particular, one advantage offered by ghost nodes that none of the other solutions I've looked at do is that it allows and even encourages non-monolithic designs. Here's what I mean: when children are dynamically generated in something like a ForEach loop or an If-condition, they need to be properly inserted into their parent node, and ordered properly with respect to their non-dynamic siblings. This has to work even if the dynamically-generated children are the empty set, or if the generated children of the previous generation were the empty set. This requires that the parent be aware of what's going on dynamically with its children, to be notified when changes take place, and to have metadata that allows it to order things correctly.

This gets further complicated by the fact that the hierarchy levels of the display tree and the hierarchy levels of template execution might not be a 1:1 mapping: it's common in the React world, for example, to have templates that do nothing but call other templates, sometimes for several levels (these intermediate templates do, however, add value in the form of additional state, effects, callbacks and so on). So you might have a case where the "parent" of a display node doesn't directly correspond to the "parent" of a template node or VDOM node. This means that the repositioning of dynamic children has to search upward in the hierarchy until they can find some parent responsible for deciding where the children should go.

With ghost nodes, all of that complexity lives in the layout extraction traversal, hidden from the average user. This means that each ghost node and its children are context-free - they don't care about their parent and never need to communicate with it. This decoupling allows for a non-monolithic approach to UI construction, such that the methods used to construct a parent node doesn't have to match or coordinate the methods used to construct its children - you can mix and match.

@UkoeHB UkoeHB mentioned this pull request Oct 4, 2024
1 task
@eidloi
Copy link

eidloi commented Oct 4, 2024

@viridia nothing can justify breaking the guarantee that the node tree is the single source of truth that will end up being rendered. Especially not ghost nodes that do nothing. Your obsession with java script is commendable but bevy already rendered anything you changed in the tree and there are observers now to achieve data binding outside of systems. The reasons react and reactive systems exist do not apply to Bevy. Never did. It is simply insane to litter the tree with unknown-purpose gaps. Except for the sole purpose of supporting a fully authoritative top down management framework... where have I seen that I wonder?

In any case, there is no reason to continue this discussion, I won't stand in the way of bevy's evolution, good or bad. There is always a way forward regardless of current state and it isn't in my authority to influence how much users need to accept or adopt.

Nor am I one to provide a supporting framework anymore. I have already pulled sickle_ui so you got what you wanted. I also commend your malicious ingenuity and manipulative communication skills that managed to kill your only "competition" in your quest for dominance (even if it wasn't competing). Surprised that I didn't like ghost nodes? Of course you were. You finally have 30 users and you are sad to stop supporting them? Like you ever had to? Guess what ;)

Also, I've already left the discord once because nobody can really say anything over you shouting wall of texts and only popped back to announce the deprecation. I have left again and have no intention (or reason) to return after this.

I would be glad you are on your way to achieve your dream game if it didn't involve destroying others'.

I offer no apology for the personal outburst, nor for the content of it. I held it as long as humanely possible, tried to find workarounds, but push came to shove.

Cheers.

@eidloi
Copy link

eidloi commented Oct 4, 2024

@cart, I won't accept your apology since you have nothing to apologize for. I was prepared to rewrite the entire bevy_ui & text for my own purposes should the need arise (upset about it, yes, but prepared). In fact I made a PoC for the text over a month ago. sickle_ui's user base (if any) is another question, but I think as long as there is an alternative nobody will care too much.

robtfm pushed a commit to robtfm/bevy that referenced this pull request Oct 4, 2024
# Objective

- Fixes bevyengine#14826 
- For context, see bevyengine#15238

## Solution
Add a `GhostNode` component to `bevy_ui` and update all the relevant
systems to use it to traverse for UI children.

- [x] `ghost_hierarchy` module
  - [x] Add `GhostNode`
- [x] Add `UiRootNodes` system param for iterating (ghost-aware) UI root
nodes
- [x] Add `UiChildren` system param for iterating (ghost-aware) UI
children
- [x] Update `layout::ui_layout_system`
  - [x] Use ghost-aware root nodes for camera updates
  - [x] Update and remove children in taffy
    - [x] Initial spawn
    - [x] Detect changes on nested UI children
- [x] Use ghost-aware children traversal in
`update_uinode_geometry_recursive`
- [x] Update the rest of the UI systems to use the ghost hierarchy
  - [x] `stack::ui_stack_system`
  - [x] `update::`
    - [x] `update_clipping_system`
    - [x] `update_target_camera_system`
  - [x] `accessibility::calc_name`

## Testing
- [x] Added a new example `ghost_nodes` that can be used as a testbed.
- [x] Added unit tests for _some_ of the traversal utilities in
`ghost_hierarchy`
- [x] Ensure this fulfills the needs for currently known use cases
  - [x] Reactivity libraries (test with `bevy_reactor`)
- [ ] Text spans (mentioned by koe [on
discord](https://discord.com/channels/691052431525675048/1285371432460881991/1285377442998915246))
  
---
## Performance
[See comment
below](bevyengine#15341 (comment))

## Migration guide
Any code that previously relied on `Parent`/`Children` to iterate UI
children may now want to use `bevy_ui::UiChildren` to ensure ghost nodes
are skipped, and their first descendant Nodes included.

UI root nodes may now be children of ghost nodes, which means
`Without<Parent>` might not query all root nodes. Use
`bevy_ui::UiRootNodes` where needed to iterate root nodes instead.

## Potential future work
- Benchmarking/optimizations of hierarchies containing lots of ghost
nodes
- Further exploration of UI hierarchies and markers for root nodes/leaf
nodes to create better ergonomics for things like `UiLayer` (world-space
ui)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
@viridia
Copy link
Contributor

viridia commented Oct 4, 2024

@eidloi All I can say is that I am sad to see sickle_ui go. I know a lot of people thought very highly of it.

@cart
Copy link
Member

cart commented Oct 4, 2024

I'm locking this thread as it has become too contentious. On the topic of Ghost Nodes, the final state of things is "they are still experimental and we are not yet committed to adopting them". The maintainers and I are discussing whether to revert or to adjust how we expose them to avoid people taking dependencies on them (or feeling pressure to adapt to them) before we're actually committed.

@eidloi, you have violated our code of conduct (as I am sure you are aware). I'm giving you a temporary week long block to let you cool off. Please don't let it happen again.

@bevyengine bevyengine locked as too heated and limited conversation to collaborators Oct 4, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A-UI Graphical user interfaces, styles, layouts, and widgets C-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes M-Needs-Release-Note Work that should be called out in the blog due to impact S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ghost nodes: layout- and rendering-ignored entities in hierarchies
7 participants