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

Refactor App and SubApp internals for better separation #9202

Merged
merged 5 commits into from
Mar 31, 2024

Conversation

maniwani
Copy link
Contributor

@maniwani maniwani commented Jul 18, 2023

Objective

This is a necessary precursor to #9122 (this was split from that PR to reduce the amount of code to review all at once).

Moving !Send resource ownership to App will make it unambiguously !Send. SubApp must be Send, so it can't wrap App.

Solution

Refactor App and SubApp to not have a recursive relationship. Since SubApp no longer wraps App, once !Send resources are moved out of World and into App, SubApp will become unambiguously Send.

There could be less code duplication between App and SubApp, but that would break App method chaining.

Changelog

  • SubApp no longer wraps App.
  • App fields are no longer publicly accessible.
  • App can no longer be converted into a SubApp.
  • Various methods now return references to a SubApp instead of an App.

Migration Guide

  • To construct a sub-app, use SubApp::new(). App can no longer convert into SubApp.
  • If you implemented a trait for App, you may want to implement it for SubApp as well.
  • If you're accessing app.world directly, you now have to use app.world() and app.world_mut().
  • App::sub_app now returns &SubApp.
  • App::sub_app_mut now returns &mut SubApp.
  • App::get_sub_app now returns Option<&SubApp>.
  • App::get_sub_app_mut now returns Option<&mut SubApp>.

@maniwani maniwani added C-Code-Quality A section of code that is hard to understand or change A-App Bevy apps and plugins C-Breaking-Change A breaking change to Bevy's public API that needs to be noted in a migration guide X-Controversial There is active debate or serious implications around merging this PR labels Jul 18, 2023
@github-actions
Copy link
Contributor

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

@maniwani maniwani force-pushed the refactor-app-and-sub-app branch 3 times, most recently from 974bf3a to a0f986a Compare July 18, 2023 23:52
@github-actions
Copy link
Contributor

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

@github-actions
Copy link
Contributor

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

@alice-i-cecile alice-i-cecile added this to the 0.12 milestone Jul 19, 2023
@maniwani maniwani marked this pull request as ready for review July 19, 2023 18:14
Copy link
Member

@JoJoJet JoJoJet left a comment

Choose a reason for hiding this comment

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

After scanning through this a couple of times, the code checks out, and it seems well-motivated.

Comment on lines +104 to +113
sub_apps: SubApps {
main: SubApp::new(),
sub_apps: HashMap::new(),
},
Copy link
Member

Choose a reason for hiding this comment

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

What's the SubApps struct for? How come these fields aren't just stored directly under App?

Copy link
Contributor Author

@maniwani maniwani Jul 22, 2023

Choose a reason for hiding this comment

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

See the App::into_parts method in #9122. I was asked to split this part of the changes into a separate PR. In #9122, updating an App involves splitting it into its Send and !Send halves (App is !Send). SubApps is the Send half.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I understand the motivation behind this PR. I'm specifically asking about these two fields.

Why is it defined like this

struct App {
    sub_apps: SubApps,
    ...
}
struct SubApps {
    main: SubApp,
    sub_apps: HashMap<AppLabelId, SubApp>,
}

instead of like this?

struct App {
    main: SubApp,
    sub_apps: HashMap<AppLabelId, SubApp>,
    ...
}

Copy link
Contributor Author

@maniwani maniwani Jul 22, 2023

Choose a reason for hiding this comment

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

It's so you don't have to write the contents of SubApps::update by hand in each runner (it replaces App::update since runners basically can't use that after #9122). If you'd like to get rid of the sub_apps.sub_apps, please suggest a different composition that still avoids boilerplate.

Copy link
Member

Choose a reason for hiding this comment

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

Oh that makes sense. If SubApps is meant to be used externally, then there should probably be a way of accessing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Would this be better?

struct App {
    main: SubApp,
    sub_apps: SubApps,
    ...
}

#[derive(Deref, DerefMut)]
struct SubApps(HashMap<AppLabelId, SubApp>);

impl SubApps {
   fn extract(&mut self, main: &mut SubApp) {
       ...
   }
   
   ...
}

Copy link
Member

Choose a reason for hiding this comment

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

Excluding the main app from the sub-apps collection does make more sense to me, yeah.

Copy link
Contributor

Choose a reason for hiding this comment

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

What about pushing things in the other direction and try to make the main app less special?

struct App { 
    active_app_label: AppLabel, 
    sub_apps: SubApps, ... 
}

impl SubApps {
    fn extract(&mut self, main_label: AppLabel) {
        let main_app = self.0.get(main_label);
        ...
    }
}

crates/bevy_app/src/app.rs Show resolved Hide resolved
crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
crates/bevy_diagnostic/src/diagnostic.rs Show resolved Hide resolved
crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
@maniwani maniwani force-pushed the refactor-app-and-sub-app branch 2 times, most recently from 5683a8b to 4823a8c Compare July 22, 2023 22:49
Copy link
Contributor

@hymm hymm left a comment

Choose a reason for hiding this comment

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

Generally in favor of the direction of this PR. Definitely moves in the right direction to polish up the sub app abstraction.

Note: I skipped over doc comments for this review pass, but looked at everything else.


/// Runs [`Plugin::finish`] for each plugin.
pub fn finish(&mut self) {
let plugins = std::mem::take(&mut self.plugins);
Copy link
Contributor

Choose a reason for hiding this comment

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

The logic for a lot of these feels like it should be inverted. i.e. We should just be passing SubApp into the plugin methods. But rename SubApp -> App and rename the super app into something else like Bevy::new(). That would get rid of most if not all of the uses of run_as_app.

edit: actually on second thought this is might be controversial enough that it should be pushed off to a separate pr. Render plugins will need to be aware of which app they're being added to. Which will require some major changes. But the data flow is definitely a little wonky now since SubApps own plugins, but I'm fine with fixing in another pr and merging as is to unblock fixing nonsend resources.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a bigger change, yeah. Plugins can currently see everything and the various render-related plugins do currently make use of that to add things to both the main app and the rendering sub-app.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could that be achieved with an API call? something like:

impl Plugin for MyPlugin {
  fn build(&mut sub_app) {
    let render_app = sub_app.get_sibling(RenderApp);
  }
}

Comment on lines +104 to +113
sub_apps: SubApps {
main: SubApp::new(),
sub_apps: HashMap::new(),
},
Copy link
Contributor

Choose a reason for hiding this comment

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

What about pushing things in the other direction and try to make the main app less special?

struct App { 
    active_app_label: AppLabel, 
    sub_apps: SubApps, ... 
}

impl SubApps {
    fn extract(&mut self, main_label: AppLabel) {
        let main_app = self.0.get(main_label);
        ...
    }
}

Copy link
Contributor

@hymm hymm left a comment

Choose a reason for hiding this comment

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

did a review pass over the docs. Seems like there still needs to be some decision on where to put the main app?

crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
crates/bevy_app/src/sub_app.rs Outdated Show resolved Hide resolved
crates/bevy_app/src/sub_app.rs Show resolved Hide resolved
@maniwani maniwani force-pushed the refactor-app-and-sub-app branch 2 times, most recently from afe77f6 to 1ee3b95 Compare September 10, 2023 01:19
Copy link
Contributor

@hymm hymm left a comment

Choose a reason for hiding this comment

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

Willing to merge this as is to unblock #9122. There's an open question about how and where main app should be stored, but we can adjust that in follow up PRs as it probably won't effect the public apis.

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.

I like this architecture a lot better, and the code / doc quality is solid.

In particular, no longer storing App nested indefinitely in itself is really important for architectural (and UX) clarity. I agree with Hymm, moving this forward is important and this is definitely a step in the right direction.

@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 Sep 12, 2023
@maniwani maniwani force-pushed the refactor-app-and-sub-app branch 2 times, most recently from d44d1c5 to d760588 Compare September 22, 2023 21:13
Copy link
Member

@james7132 james7132 left a comment

Choose a reason for hiding this comment

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

Sorry for taking so long to review this. LGTM. Most of the outstanding comments here can be addressed in a followup PR if need be.

crates/bevy_app/src/app.rs Outdated Show resolved Hide resolved
Copy link
Member

@JoJoJet JoJoJet left a comment

Choose a reason for hiding this comment

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

LGTM still. Re-approved

@james7132 james7132 added this pull request to the merge queue Mar 31, 2024
Merged via the queue into bevyengine:main with commit 01649f1 Mar 31, 2024
27 checks passed
@alice-i-cecile alice-i-cecile removed the C-Needs-Release-Note Work that should be called out in the blog due to impact label May 27, 2024
ChristopherBiscardi added a commit to ChristopherBiscardi/bevy_ecs_tilemap that referenced this pull request Jun 7, 2024
- [9202](bevyengine/bevy#9202) changed world access to functions. [relevent line](https://github.com/bevyengine/bevy/pull/9202/files#diff-b2fba3a0c86e496085ce7f0e3f1de5960cb754c7d215ed0f087aa556e529f97fR640)
- This also surfaced [12655](bevyengine/bevy#12655) which removed `Into<AssetId<T>>` for `Handle<T>`. using a reference or .id() is the solution here.
github-merge-queue bot pushed a commit that referenced this pull request Jun 10, 2024
# Objective

- Let `init_non_send_resource` take `FromWorld` values again, not only
`Default`
- This reverts an unintended breaking change introduced in #9202

## Solution

- The resource initialized with `init_non_send_resource` requires
`FromWorld` again
mockersf pushed a commit that referenced this pull request Jun 10, 2024
# Objective

- Let `init_non_send_resource` take `FromWorld` values again, not only
`Default`
- This reverts an unintended breaking change introduced in #9202

## Solution

- The resource initialized with `init_non_send_resource` requires
`FromWorld` again
@maniwani maniwani deleted the refactor-app-and-sub-app branch June 20, 2024 00:25
zhaop added a commit to zhaop/bevy_editor_pls that referenced this pull request Jun 24, 2024
zhaop added a commit to zhaop/bevy_editor_pls that referenced this pull request Jun 24, 2024
zhaop added a commit to zhaop/bevy_editor_pls that referenced this pull request Jun 24, 2024
zhaop added a commit to zhaop/bevy_editor_pls that referenced this pull request Jun 24, 2024
zhaop added a commit to zhaop/transform-gizmo that referenced this pull request Jun 24, 2024
rparrett added a commit to StarArawn/bevy_ecs_tilemap that referenced this pull request Jul 5, 2024
* Update to 0.14.0-rc.2

* [12997](bevyengine/bevy#12997): rename `multi-threaded` to `multi_threaded`

* RenderAssets<Image> is now RenderAssets<GpuImage>

Implemented in [12827](bevyengine/bevy#12827)

* FloatOrd is now in bevy_math

implemented in [12732](bevyengine/bevy#12732)

* convert Transparent2d::dynamic_offset to extra_index

[12889](bevyengine/bevy#12889) Gpu Frustum Culling removed the dynamic_offset of Transparent2d and it became `extra_index` with the special value `PhaseItemExtraIndex::NONE`, which indicates the `None` that was here previously

* RenderPhase<Transparent2d> -> ViewSortedRenderPhases<Transparent2d>

[12453](https://github.com/StarArawn/bevy_ecs_tilemap/pull/bevyengine/bevy#12453): Render phases are now binned or sorted.

Following the changes in the `mesh2d_manual` [example](https://github.com/bevyengine/bevy/blob/ecdd1624f302c5f71aaed95b0984cbbecf8880b7/examples/2d/mesh2d_manual.rs#L357-L358): use the `ViewSortedRenderPhases` resource.

* get_sub_app_mut is now an Option

in [9202](https://github.com/StarArawn/bevy_ecs_tilemap/pull/bevyengine/bevy/pull/9202) SubApp access has changed

* GpuImage::size f32 -> u32 via UVec2

[11698](bevyengine/bevy#11698) changed `GpuImage::size` to `UVec2`.

Right above this, `Extent3d` does the same thing, so I'm taking a small leap and assuming can `as`.

* GpuMesh::primitive_topology -> key_bits/BaseMeshPipeline

[12791](bevyengine/bevy#12791) the `primitive_topology` field on `GpuMesh` was removed in favor of `key_bits` which can be constructed using `BaseMeshPipeline::from_primitive_topology`

* RenderChunk2d::prepare requires &mut MeshVertexBufferLayouts now

[12216](bevyengine/bevy#12216) introduced an argument `&mut MeshVertexBufferLayouts` to `get_mesh_vertex_buffer_layout`, which bevy_ecs_tilemap calls in `RenderChunk2d::prepare`

* into_linear_f32 -> color.0.linear().to_f32_array(),

[12163](bevyengine/bevy#12163) bevy_color was created and Color handling has changed. Specifically Color::as_linear_rgba_f32 has been removed.

LinearRgba is now its own type that can be accessed via [`linear()`](https://docs.rs/bevy/0.14.0-rc.2/bevy/color/enum.Color.html#method.linear) and then converted.

* Must specify type of VisibleEntities when accessing

[12582](bevyengine/bevy#12582) divided `VisibleEntities` into separate lists. So now we have to specify which kind of entity we want. I think we want the Mesh here, and I think we can get rid of the `.index` calls on Entity since Entity [already compares bits](https://docs.rs/bevy_ecs/0.14.0-rc.2/src/bevy_ecs/entity/mod.rs.html#173) for optimized codegen purposes. Waiting to do that until the other changes are in though so as to not change functionality until post-upgrade.

* app.world access is functions now

- [9202](bevyengine/bevy#9202) changed world access to functions. [relevent line](https://github.com/bevyengine/bevy/pull/9202/files#diff-b2fba3a0c86e496085ce7f0e3f1de5960cb754c7d215ed0f087aa556e529f97fR640)
- This also surfaced [12655](bevyengine/bevy#12655) which removed `Into<AssetId<T>>` for `Handle<T>`. using a reference or .id() is the solution here.

* We don't need `World::cell`, and it doesn't exist anymore

In [12551](bevyengine/bevy#12551) `WorldCell` was removed.

...but it turns out we don't need it or its replacement anyway.

* examples error out unless this bevy bug is addressed with these features being added

bevyengine/bevy#13728

* check_visibility is required for the entity that is renderable

As a result of [12582](bevyengine/bevy#12582) `check_visibility` must be implemented for the "renderable" tilemap entities. Doing this is trivial by taking advantage of the
existing `check_visibility` type arguments, which accept a [`QF: QueryFilter + 'static`](https://docs.rs/bevy/0.14.0-rc.2/bevy/render/view/fn.check_visibility.html).

The same `QueryFilter`` is used when checking `VisibleEntities`. I've chosen `With<TilemapRenderSettings` because presumably if the entity doesn't have a `TilemapRenderSettings` then it will not be rendering, but this could be as sophisticated or simple as we want.

For example `WithLight` is currently implemented as

```rust
pub type WithLight = Or<(With<PointLight>, With<SpotLight>, With<DirectionalLight>)>;
```

* view.view_proj -> view.clip_from_world

[13289](bevyengine/bevy#13489) introduced matrix naming changes, including `view_proj` which becomes `clip_from_world`

* color changes to make tests runnable

* clippy fix

* Update Cargo.toml

Co-authored-by: Rob Parrett <robparrett@gmail.com>

* Update Cargo.toml

Co-authored-by: Rob Parrett <robparrett@gmail.com>

* final clippy fixes

* Update Cargo.toml

Co-authored-by: Rob Parrett <robparrett@gmail.com>

* Simplify async loading in ldtk/tiled helpers

See Bevy #12550

* remove second allow lint

* rc.3 bump

* bump version for major release

* remove unused features

---------

Co-authored-by: Rob Parrett <robparrett@gmail.com>
jakobhellermann pushed a commit to jakobhellermann/bevy_editor_pls that referenced this pull request Aug 11, 2024
jakobhellermann pushed a commit to jakobhellermann/bevy_editor_pls that referenced this pull request Aug 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-App Bevy apps and plugins C-Breaking-Change A breaking change to Bevy's public API that needs to be noted in a migration guide C-Code-Quality A section of code that is hard to understand or change S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Controversial There is active debate or serious implications around merging this PR
Projects
Status: Merged PR
Development

Successfully merging this pull request may close these issues.

7 participants