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

Reliable Change Detection #54

Closed
wants to merge 23 commits into from
Closed

Conversation

alice-i-cecile
Copy link
Contributor

@alice-i-cecile alice-i-cecile commented Apr 20, 2021

Rendered

A technical post on solving reliable change detection for Bevy.

@alice-i-cecile alice-i-cecile added the content Words to fill the page label Apr 20, 2021
@alice-i-cecile alice-i-cecile marked this pull request as draft April 20, 2021 06:46
@sixfold-origami
Copy link
Contributor

Closes #52

@sixfold-origami sixfold-origami linked an issue Apr 20, 2021 that may be closed by this pull request
@alice-i-cecile alice-i-cecile marked this pull request as ready for review May 3, 2021 04:26
@alice-i-cecile
Copy link
Contributor Author

Todo: add ring buffer diagram.

@alice-i-cecile
Copy link
Contributor Author

@alice-i-cecile
Copy link
Contributor Author

Steal simpler explanation of the algorithm from the talk.

@netlify
Copy link

netlify bot commented Jun 16, 2022

Deploy Preview for leafwing-studios ready!

Name Link
🔨 Latest commit 4d22787
🔍 Latest deploy log https://app.netlify.com/sites/leafwing-studios/deploys/62aa9a2fc33da9000a87001f
😎 Deploy Preview https://deploy-preview-54--leafwing-studios.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

Copy link
Contributor

@TimJentzsch TimJentzsch left a comment

Choose a reason for hiding this comment

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

Not sure if you're still working on this, but I did a first pass.

Definitely an interesting write-up, especially since I tried to find out just recently if it only works until the end of the frame or if it "wraps around". (Of course the docs had the answer though :D)

Comments are mostly suggestions to link to the docs where it makes sense.
I purposefully used links to the 0.8 docs, so that the links don't break (or stop making sense) in future Bevy versions.

draft = true
+++

**An abridged version of this post was also presented as a 10 minute talk for the Rust East Coast meetup group ([slides](https://docs.google.com/presentation/d/1gggEX4dfOaBdKcZJySm8i7TmxIJkyModEcl8dDkrqQw/edit#slide=id.p), [video](TODO: add link))*.
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't forget the TODO here :)

Copy link
Contributor

Choose a reason for hiding this comment

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

The Leafwing logo on the Docs is the old one, but it's probably weird to update the slides after the talk


**An abridged version of this post was also presented as a 10 minute talk for the Rust East Coast meetup group ([slides](https://docs.google.com/presentation/d/1gggEX4dfOaBdKcZJySm8i7TmxIJkyModEcl8dDkrqQw/edit#slide=id.p), [video](TODO: add link))*.

Over the past half-year or so, I've dedicated much of my time to improving [Bevy](https://bevyengine.org/), an ECS-first game engine in Rust.
Copy link
Contributor

Choose a reason for hiding this comment

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

The "past half-year" is probably not accurate anymore

Comment on lines +29 to +31
// TODO: WRITE EXAMPLE
// Text-only
// Spawning system, changes creation
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't forget the TODO here :)

Today, I want to talk about one of the features I helped build and love using: **reliable change detection**.

For those of you who've never used Bevy before, all of the game logic occurs in **systems**: ordinary Rust functions that are automatically scheduled to run each frame.
These receive their data from the central ECS data store by requesting access to specific data, typically via **queries**, which carefully slice the data and request only the specific data needed.
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider linking to Query here:

Suggested change
These receive their data from the central ECS data store by requesting access to specific data, typically via **queries**, which carefully slice the data and request only the specific data needed.
These receive their data from the central ECS data store by requesting access to specific data, typically via [**queries**](https://docs.rs/bevy/0.8.0/bevy/prelude/struct.Query.html), which carefully slice the data and request only the specific data needed.

As we build out our game, we can combine these systems to spectacular effect, carefully slicing our data and performing elaborate feats of automatically-parallelized behavior-first execution.

By default though, queries fetch data from *all* of the entities with the appropriate components.
This can be quite expensive when we only need to operate on a subset, even if we carefully slice our queries using `With` or `Without` **query filters**.
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider linking to the docs here:

Suggested change
This can be quite expensive when we only need to operate on a subset, even if we carefully slice our queries using `With` or `Without` **query filters**.
This can be quite expensive when we only need to operate on a subset, even if we carefully slice our queries using [`With`](https://docs.rs/bevy/0.8.0/bevy/prelude/struct.With.html) or [`Without`](https://docs.rs/bevy/0.8.0/bevy/prelude/struct.Without.html) **query filters**.

To do so, we store timers in three separate locations:

* On the `World` as a global indicator of current time. Whenever a system begins execution, [this increments once](https://github.com/bevyengine/bevy/pull/1471/files#diff-5499ffc12ee4011981ff6d5069a1986197d824648c65ed24056e6b2772b3cd81R146).
* On each piece of `Resource` or `Component` data, [marking when the data was last changed](https://github.com/bevyengine/bevy/pull/1471/files#diff-0e94997025571f709abd7cac97f03bb4e8ec8bf29650068a7e5ec07170011892R137) in terms of the global timer.
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider linking to the docs here:

Suggested change
* On each piece of `Resource` or `Component` data, [marking when the data was last changed](https://github.com/bevyengine/bevy/pull/1471/files#diff-0e94997025571f709abd7cac97f03bb4e8ec8bf29650068a7e5ec07170011892R137) in terms of the global timer.
* On each piece of [`Res`ource](https://docs.rs/bevy/0.8.0/bevy/prelude/struct.Res.html) or [`Component`](https://docs.rs/bevy/0.8.0/bevy/prelude/trait.Component.html) data, [marking when the data was last changed](https://github.com/bevyengine/bevy/pull/1471/files#diff-0e94997025571f709abd7cac97f03bb4e8ec8bf29650068a7e5ec07170011892R137) in terms of the global timer.


* On the `World` as a global indicator of current time. Whenever a system begins execution, [this increments once](https://github.com/bevyengine/bevy/pull/1471/files#diff-5499ffc12ee4011981ff6d5069a1986197d824648c65ed24056e6b2772b3cd81R146).
* On each piece of `Resource` or `Component` data, [marking when the data was last changed](https://github.com/bevyengine/bevy/pull/1471/files#diff-0e94997025571f709abd7cac97f03bb4e8ec8bf29650068a7e5ec07170011892R137) in terms of the global timer.
* On each `System`, marking when the system last ran in terms of the global timer.
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider linking to the docs here:

Suggested change
* On each `System`, marking when the system last ran in terms of the global timer.
* On each [`System`](https://docs.rs/bevy/0.8.0/bevy/prelude/trait.System.html), marking when the system last ran in terms of the global timer.


1. **Ergonomic.** Yes, all of the magic happens behind-the-scenes.
2. **Automatic.** Yes, there's no need to opt in.
3. **Low memory overhead.** Yes, we're only storing a single u32 per component, no matter how many systems we have.
Copy link
Contributor

Choose a reason for hiding this comment

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

Formatting:

Suggested change
3. **Low memory overhead.** Yes, we're only storing a single u32 per component, no matter how many systems we have.
3. **Low memory overhead.** Yes, we're only storing a single [`u32`](https://doc.rust-lang.org/std/primitive.u32.html) per component, no matter how many systems we have.

No matter the scenario, this solution detects each change *exactly* once per system if the data has been mutably accessed at least once since the system last ran.

What's that? Oh right, I must apologize: there is one case where a change may be missed with a warning.
If, while your system is asleep, more than [`u32::MAX * 3 / 4`](https://github.com/bevyengine/bevy/pull/1471#issuecomment-787009753) (3221225471) systems have run, you will miss changes that occurred.
Copy link
Contributor

Choose a reason for hiding this comment

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

Formatting:

Suggested change
If, while your system is asleep, more than [`u32::MAX * 3 / 4`](https://github.com/bevyengine/bevy/pull/1471#issuecomment-787009753) (3221225471) systems have run, you will miss changes that occurred.
If, while your system is asleep, more than [`u32::MAX * 3 / 4`](https://github.com/bevyengine/bevy/pull/1471#issuecomment-787009753) (3,221,225,471) systems have run, you will miss changes that occurred.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, why is it 3 / 4?

* On each `System`, marking when the system last ran in terms of the global timer.

If the data's change tick is greater than the system's change tick, the data has changed since it was last processed.
We use [wrapping subtraction]((https://github.com/bevyengine/bevy/pull/1471/files#diff-0e94997025571f709abd7cac97f03bb4e8ec8bf29650068a7e5ec07170011892R137) to determine what "greater than" means, giving us **ring buffer** behavior, allowing our change detection to continue functioning indefinitely rather than running out of space as time goes on.
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo:

Suggested change
We use [wrapping subtraction]((https://github.com/bevyengine/bevy/pull/1471/files#diff-0e94997025571f709abd7cac97f03bb4e8ec8bf29650068a7e5ec07170011892R137) to determine what "greater than" means, giving us **ring buffer** behavior, allowing our change detection to continue functioning indefinitely rather than running out of space as time goes on.
We use [wrapping subtraction](https://github.com/bevyengine/bevy/pull/1471/files#diff-0e94997025571f709abd7cac97f03bb4e8ec8bf29650068a7e5ec07170011892R137) to determine what "greater than" means, giving us **ring buffer** behavior, allowing our change detection to continue functioning indefinitely rather than running out of space as time goes on.

@alice-i-cecile
Copy link
Contributor Author

Thanks for the feedback! I think I'm going to close this out though; not sure it has enough value at this point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
content Words to fill the page
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reliable change detection
4 participants