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

[Merged by Bors] - Make paused timers update just_finished on tick #4445

Closed
wants to merge 3 commits into from

Conversation

tim-blackbird
Copy link
Contributor

@tim-blackbird tim-blackbird commented Apr 8, 2022

Objective

Make timers update just_finished on tick, even if paused.
Fixes #4436

Solution

just_finished() returns times_finished > 0. So I:

  • Renamed times_finished to times_finished_this_tick to reduce confusion.
  • Set times_finished_this_tick to 0 on tick when paused.
  • Additionally set finished to false if the timer is repeating.

Notably this change broke none of the existing tests, so I added a couple for this.

Files changed shows a lot of noise because of the rename. Check the first commit for the relevant changes.

Migration Guide

Timer::times_finished has been renamed to Timer::times_finished_this_tick for clarity.

@github-actions github-actions bot added the S-Needs-Triage This issue needs to be labelled label Apr 8, 2022
@alice-i-cecile alice-i-cecile added C-Bug An unexpected or incorrect behavior A-Core Common functionality for all bevy apps and removed S-Needs-Triage This issue needs to be labelled labels Apr 8, 2022
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.

Both of the tests look good, but the fix is a bit questionable to me.

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.

Aha, that makes way more sense. LGTM now.

@tim-blackbird
Copy link
Contributor Author

It would be great if this could make it into 0.7.
If we decide we do want a times_finished that indicates the amount of times a timer has finished since it's last reset for 0.8. We'll end up with a breaking change that still compiles 😧

@alice-i-cecile
Copy link
Member

It would be great if this could make it into 0.7.

Needs a second approval :) You should consider asking on Discord in #general-dev.

@hymm
Copy link
Contributor

hymm commented Apr 11, 2022

I'm not sure about adding this functionality to paused. Real stopwatches don't change the state when they're paused. Only when the reset button is pushed, so holding the finished state makes sense. To me it feels like this should be a separate function that can be called to reset finished.

@tim-blackbird
Copy link
Contributor Author

tim-blackbird commented Apr 12, 2022

The finished state will still be held even with this pr. Only just_finished will be updated.

Unless the the timer is repeating, in which case using finished() usually behaves like just_finished() as mentioned in the example.
in this pr I made it so it still behaves the same way, even when paused. (I'm not entirely sold on my decision here)

Having just_finished() return true for more than one tick, (Which contradicts it's doc comment!) is IMO suprising and in the usecases I can think of, undesired.

As an example:
let's say there is a system that spawns one enemy every few seconds using a repeating timer's just_finished().
And if the player pauses the game, this timer is paused.
Before this pr, if the player pauses the game on the frame the enemy is going to be spawned, an enemy will be spawned every-frame as long as the player stays in the pause menu.

See the linked issue(#4436) for an explanation of the problem by @Madadog.

@hymm
Copy link
Contributor

hymm commented Apr 12, 2022

Yeah my previous suggestion was a little confused. But setting times_finished to 0 feels a little surprising though. It should still report the number of times the timer finished even if it is paused.

I think I would prefer if we just decouple the state of just_finished from times_finished. i.e. add a separate bool for just_finished.

Also what is the reasoning to setting finished to false if it's paused and repeating?

@tim-blackbird
Copy link
Contributor Author

tim-blackbird commented Apr 12, 2022

Oh, no. Another victim of the confusingly named variable times_finished.
Sorry if that sounded snarky. I think I can speak for @alice-i-cecile and myself that we were very confused at first also.

I hope you did notice my latest commit renaming times_finished to times_finished_this_tick. If you're still having trouble, do read the doc comment on the times_finished_this_tick() method, and it's tests.

I think I would prefer if we just decouple the state of just_finished from times_finished. i.e. add a separate bool for just_finished.

When I started making this change this was exactly what I was going for, but as I was trying to do so I read the doc comment/tests for times_finished and realized that it wasn't what I though it was, and it's very clear to me now that I'm not the only one.

(Pinging @kokounet as they introduced times_finished)

Also what is the reasoning to setting finished to false if it's paused and repeating?

Purely because it would make this statement in the timers example, no longer true.
I am now leaning more to rephrasing the example and removing the special case I coded in for this.

@hymm
Copy link
Contributor

hymm commented Apr 12, 2022

yeah, definitely a bit confusing. So if we pause the timer the internal elapsed time might say evaluate to time_finished_this_tick to 2, but since it's paused it reports 0. But when we unpause the time it'll report 2 or more after the timer is unpaused and ticked, because the internal state hasn't been reset.

What we want is for a tick to be a noop to the public api. So is reporting the timer as not having finished correct then? It might be? Honestly not sure. The timer actually finished before you paused the timer...

Really need to see some use cases for this API to know for sure.

@tim-blackbird
Copy link
Contributor Author

Sorry, I should have explained the purpose of times_finished_this_tick better.

Timers do not track how many times they have finished, period, this has not been added (yet).
Only how many times they finished within the latest tick.

So, times_finished_this_tick can be used to see whether a timer finished multiple times over in one tick.
finished and just_finished cannot do this.

But I am clearly failing terribly at explaining this with words. I hope these code examples do the trick.

let mut t = Timer::from_seconds(1.0, true);

if t.tick(Duration::from_secs_f32(3.0)).just_finished() {
    // only reached once!!!
}

for _ in 0..t.tick(Duration::from_secs_f32(3.0)).times_finished_this_tick() {
    // reached three times!!!
}

t.tick(Duration::from_secs_f32(0.0));
assert_eq!(t.times_finished_this_tick(), 0);

t.tick(Duration::from_secs_f32(3.0));
assert_eq!(t.times_finished_this_tick(), 3);

t.tick(Duration::from_secs_f32(69.0));
assert_eq!(t.times_finished_this_tick(), 69);

@kokounet
Copy link
Contributor

I definitely agree, that name is confusing. At that time I did not think it could be interpreted as the total number of wraps for repeating timers 😅 as I didn't see any use case for it. It's definitely a bad name if it's required to read the doc to understand what it does.
Though I'm not a huge fan of the new name as it is a bit verbose, but still it's better than the current one !

@hymm
Copy link
Contributor

hymm commented Apr 14, 2022

I'm sorry to make you explain so much. This was definitely a me problem. I was getting my mental model confused with timers from other programs. Reseting times_finished_this_tick makes sense because this tick is the current/last call to tick, which is a no op if the timer is paused, so there definitely can't be any finishes on a paused tick.

@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 Apr 14, 2022
@tim-blackbird tim-blackbird changed the title Make timers update just_finished on tick, even if paused. Make paused timers update just_finished on tick Apr 14, 2022
@hymm
Copy link
Contributor

hymm commented Apr 23, 2022

Should this have a migration guide (label) for the rename?

@alice-i-cecile alice-i-cecile added the C-Breaking-Change A breaking change to Bevy's public API that needs to be noted in a migration guide label Apr 23, 2022
@alice-i-cecile
Copy link
Member

@devil-ira please edit your PR description to include the following migration guide section when you get a chance :)

Migration Guide

Timer::times_finished has been renamed to Timer::times_finished_this_tick for clarity.

@alice-i-cecile
Copy link
Member

bors r+

bors bot pushed a commit that referenced this pull request Apr 26, 2022
# Objective
Make timers update `just_finished` on tick, even if paused.
Fixes #4436

## Solution
`just_finished()` returns `times_finished > 0`. So I:
 * Renamed `times_finished` to `times_finished_this_tick` to reduce confusion.
 * Set `times_finished_this_tick` to `0` on tick when paused.
 * Additionally set `finished` to `false` if the timer is repeating.

Notably this change broke none of the existing tests, so I added a couple for this.

Files changed shows a lot of noise because of the rename. Check the first commit for the relevant changes.

Co-authored-by: devil-ira <justthecooldude@gmail.com>
@bors bors bot changed the title Make paused timers update just_finished on tick [Merged by Bors] - Make paused timers update just_finished on tick Apr 26, 2022
@bors bors bot closed this Apr 26, 2022
exjam pushed a commit to exjam/bevy that referenced this pull request May 22, 2022
# Objective
Make timers update `just_finished` on tick, even if paused.
Fixes bevyengine#4436

## Solution
`just_finished()` returns `times_finished > 0`. So I:
 * Renamed `times_finished` to `times_finished_this_tick` to reduce confusion.
 * Set `times_finished_this_tick` to `0` on tick when paused.
 * Additionally set `finished` to `false` if the timer is repeating.

Notably this change broke none of the existing tests, so I added a couple for this.

Files changed shows a lot of noise because of the rename. Check the first commit for the relevant changes.

Co-authored-by: devil-ira <justthecooldude@gmail.com>
@tim-blackbird tim-blackbird deleted the timer_changes branch November 8, 2022 21:52
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
# Objective
Make timers update `just_finished` on tick, even if paused.
Fixes bevyengine#4436

## Solution
`just_finished()` returns `times_finished > 0`. So I:
 * Renamed `times_finished` to `times_finished_this_tick` to reduce confusion.
 * Set `times_finished_this_tick` to `0` on tick when paused.
 * Additionally set `finished` to `false` if the timer is repeating.

Notably this change broke none of the existing tests, so I added a couple for this.

Files changed shows a lot of noise because of the rename. Check the first commit for the relevant changes.

Co-authored-by: devil-ira <justthecooldude@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Core Common functionality for all bevy apps C-Breaking-Change A breaking change to Bevy's public API that needs to be noted in a migration guide C-Bug An unexpected or incorrect behavior 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.

Timer::just_finished() returns true forever when paused during finish tick
4 participants