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 a method for detecting changes within a certain scope #11687

Merged
merged 2 commits into from Feb 12, 2024

Conversation

JoJoJet
Copy link
Member

@JoJoJet JoJoJet commented Feb 3, 2024

Objective

Bevy's change detection functionality is invaluable for writing robust apps, but it only works in the context of systems and exclusive systems. Oftentimes it is necessary to detect changes made in earlier code without having to place the code in separate systems, but it is not currently possible to do so since there is no way to set the value of World::last_change_tick.

World::clear_trackers allows you to update the change tick, but this has unintended side effects, since it irreversibly affects the behavior of change and removal detection for the entire app.

Solution

Add a method World::last_change_tick_scope. This allows you to set last_change_tick to a specific value for a region of code. To ensure that misuse doesn't break unrelated functions, we restore the world's original change tick at the end of the provided scope.

Example

A function that uses this to run an update loop repeatedly, allowing each iteration of the loop to react to changes made in the previous loop iteration.

fn update_loop(
    world: &mut World,
    mut update_fn: impl FnMut(&mut World) -> std::ops::ControlFlow<()>,
) {
    let mut last_change_tick = world.last_change_tick();

    // Repeatedly run the update function until it requests a break.
    loop {
        // Update once.
        let control_flow = world.last_change_tick_scope(last_change_tick, |world| {
            update_fn(world)
        });

        // End the loop when the closure returns `ControlFlow::Break`.
        if control_flow.is_break() {
            break;
        }

        // Increment the change tick so the next update can detect changes from this update.
        last_change_tick = world.change_tick();
        world.increment_change_tick();
    }
}

Changelog

  • Added World::last_change_tick_scope, which allows you to specify the reference for change detection within a certain scope.

@alice-i-cecile alice-i-cecile added C-Enhancement A new feature A-ECS Entities, components, systems, and events C-Usability A simple quality-of-life change that makes Bevy easier to use and removed C-Enhancement A new feature labels Feb 4, 2024
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.

Clever implementation with the Drop-implementing struct. Good choice there. It's also nice to see it finding a home in the exclusive system internals. And great doc test!

I'd like to hear more about the motivations, if you can share them, but I'm happy to approve this as is.

@JoJoJet
Copy link
Member Author

JoJoJet commented Feb 4, 2024

I'd like to hear more about the motivations, if you can share them, but I'm happy to approve this as is.

Sure. For our dioxus plugin, we need to rerender UI elements any time that world data they access changes. Since the dioxus app is allowed to modify the world, we need to repeatedly update the vdom until all of the world data it accesses stops changing. In order to implement this, we need to be able to detect changes made in previous iterations of the update loop.

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.

I feel like it would be better if we could encapsulate incrementing the change tick correctly in this function too as it feels like something that is easy to get wrong. But this functionality is already pretty niche, so fine with it how it is.

@hymm hymm 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 Feb 11, 2024
@JoJoJet
Copy link
Member Author

JoJoJet commented Feb 11, 2024

I wanted this function to do only one thing because I feel like there could easily be someone who would want to update last_change_tick but not the current change tick

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Feb 12, 2024
Merged via the queue into bevyengine:main with commit 9c22573 Feb 12, 2024
24 checks passed
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-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
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants