Hekili Priority Helper

Hekili Priority Helper

44M Downloads

Add "Cooldown Spiral" option for Delays

ShmooDude opened this issue · 9 comments

commented

This is primarily for energy based classes (in my case, Feral Druid) because their ability delay isn't generally tied to ability cooldowns or the GCD.

It was actually fairly trivial to add the functionality. I've created a proof of concept here:
https://github.com/ShmooDude/hekili/tree/Cooldown-Spiral

I set it up under the "Show Text (Countdown)" option and enable "Fade as Unusable" will make it display how I'm expecting it to look.

I'd suggest adding it as an additional Checkbox along side "Fade as Unusable" and have it grey out (and force on) that option when enabled.

commented
commented

One thing to keep in mind is there is occasionally jerkiness around the initial icon change. Often times this is caused by one of two things.

First, the GCD starts on the game detecting (client side) a successful ability attempt, before anything actually happens. This can easily be seen by creating a macro that dumps the spell cooldown of an ability both before and after the /cast line. Even an abilities own cooldown isn't visible yet but the GCD starts anyhow (probably to maintain responsiveness in the UI).

Second, because energy is sent as an integer, there's an inherent instability in the delay. This can already be seen on the current "Show Text (Countdown)" setting with the countdown value not progressing linearly. These jumps tend to be more severe at the start of the cooldown than towards the end and is simply a limitation of the energy API.

All that said, I still find it far preferable to have the cooldown spiral than without, despite these inherent limitations.

commented

I'm going to think about ways to impact that instability. For instance, when energy (or any other power) updates, if the increase is math.floor( energy.regen ) or math.ceil( energy.regen ) we can assume that it's a natural resource tick and base our energy forecasting from that time rather than from the present moment. That may smooth out +/- 0.1s of fluctuation.

commented

What do you mean by "that time" and "present moment?"

Ironically, I've actually found the best way to smooth it out is to do the opposite. UNIT_POWER_FREQUENT at 60 FPS generally updates every 1/10th of a second. UNIT_POWER_UPDATE on the other hand updates with non-regen gain/loss, and occasionally (every ~2 seconds?) for regeneration. Below is an example where I used Thrash to burn 40 energy from full and then regenerated it. It has the associated events/timestamps. Even if you calculate from each tick of regen you'll get that +/- 0.1s fluctuation and occasionally more.

I've tried before to smooth it out such as calculating how long since the energy was updated (which I think is what you're proposing?) and adding what theoretically should have been regenerated between then and the next update (trying to estimate the fractional power regenerated). That didn't really help as much as I thought it would. What I ultimately ended up doing in Ovale was to have it keep track of the energy using the UNIT_POWER_FREQUENT event, but only have it update the suggestion when an UNIT_POWER_UPDATE event fired (or some other event that might change what should be suggested).

Ultimately, the problem boils down to that the difference between 1 energy regenerated per 1/10th of a second and 2 is enough to cause the instability and I'm not sure any amount of math on our side can make up for the imprecise data.

OvalePower: 685230.796000 UNIT_POWER_FREQUENT: 60 -> 60 (energy).
OvalePower: 685230.796000 UNIT_POWER_UPDATE: 60 -> 60 (energy).
OvalePower: 685230.796000 UNIT_POWER_FREQUENT: 60 -> 60 (energy).
OvalePower: 685230.862000 UNIT_POWER_FREQUENT: 60 -> 61 (energy).
OvalePower: 685230.963000 UNIT_POWER_FREQUENT: 61 -> 62 (energy).
OvalePower: 685231.063000 UNIT_POWER_FREQUENT: 62 -> 64 (energy).
OvalePower: 685231.163000 UNIT_POWER_FREQUENT: 64 -> 65 (energy).
OvalePower: 685231.263000 UNIT_POWER_FREQUENT: 65 -> 66 (energy).
OvalePower: 685231.364000 UNIT_POWER_FREQUENT: 66 -> 67 (energy).
OvalePower: 685231.464000 UNIT_POWER_FREQUENT: 67 -> 69 (energy).
OvalePower: 685231.564000 UNIT_POWER_FREQUENT: 69 -> 70 (energy).
OvalePower: 685231.664000 UNIT_POWER_FREQUENT: 70 -> 71 (energy).
OvalePower: 685231.764000 UNIT_POWER_FREQUENT: 71 -> 72 (energy).
OvalePower: 685231.865000 UNIT_POWER_FREQUENT: 72 -> 74 (energy).
OvalePower: 685231.965000 UNIT_POWER_FREQUENT: 74 -> 75 (energy).
OvalePower: 685232.065000 UNIT_POWER_FREQUENT: 75 -> 76 (energy).
OvalePower: 685232.166000 UNIT_POWER_FREQUENT: 76 -> 77 (energy).
OvalePower: 685232.266000 UNIT_POWER_FREQUENT: 77 -> 79 (energy).
OvalePower: 685232.366000 UNIT_POWER_FREQUENT: 79 -> 80 (energy).
OvalePower: 685232.467000 UNIT_POWER_FREQUENT: 80 -> 81 (energy).
OvalePower: 685232.533000 UNIT_POWER_FREQUENT: 81 -> 82 (energy).
OvalePower: 685232.533000 UNIT_POWER_UPDATE: 82 -> 82 (energy).
OvalePower: 685232.533000 UNIT_POWER_FREQUENT: 82 -> 82 (energy).
OvalePower: 685232.634000 UNIT_POWER_FREQUENT: 82 -> 83 (energy).
OvalePower: 685232.734000 UNIT_POWER_FREQUENT: 83 -> 84 (energy).
OvalePower: 685232.834000 UNIT_POWER_FREQUENT: 84 -> 85 (energy).
OvalePower: 685232.934000 UNIT_POWER_FREQUENT: 85 -> 86 (energy).
OvalePower: 685233.034000 UNIT_POWER_FREQUENT: 86 -> 88 (energy).
OvalePower: 685233.134000 UNIT_POWER_FREQUENT: 88 -> 89 (energy).
OvalePower: 685233.235000 UNIT_POWER_FREQUENT: 89 -> 90 (energy).
OvalePower: 685233.335000 UNIT_POWER_FREQUENT: 90 -> 92 (energy).
OvalePower: 685233.335000 UNIT_POWER_UPDATE: 92 -> 92 (energy).
OvalePower: 685233.335000 UNIT_POWER_FREQUENT: 92 -> 92 (energy).
OvalePower: 685233.435000 UNIT_POWER_FREQUENT: 92 -> 93 (energy).
OvalePower: 685233.535000 UNIT_POWER_FREQUENT: 93 -> 94 (energy).
OvalePower: 685233.635000 UNIT_POWER_FREQUENT: 94 -> 95 (energy).
OvalePower: 685233.735000 UNIT_POWER_FREQUENT: 95 -> 96 (energy).
OvalePower: 685233.836000 UNIT_POWER_FREQUENT: 96 -> 98 (energy).
OvalePower: 685233.936000 UNIT_POWER_FREQUENT: 98 -> 99 (energy).
OvalePower: 685234.036000 UNIT_POWER_UPDATE: 99 -> 100 (energy).
OvalePower: 685234.036000 UNIT_POWER_FREQUENT: 100 -> 100 (energy).
OvalePower: 685234.554000 UNIT_POWER_UPDATE: 100 -> 100 (energy).
OvalePower: 685234.554000 UNIT_POWER_FREQUENT: 100 -> 100 (energy).

That's with an energy regen of 12.461736679077
commented

For the first part, a cooldown spiral has a start time and a duration. What is the duration of a delay? (Your solution is simple enough, and I suppose the CD spiral deals with a collapsing duration just fine, so I guess that makes sense.)

For the second part, yeah, that was the basic idea. Too bad.

commented

What do you think about the following tweak to your solution:

UI.lua, lines 1181 - 1183:

if i == 1 and rec.exact_time and start + duration < rec.exact_time then
    duration = rec.exact_time - start
end

I got the impression from your solution that it may have been double-dipping; adding the delay (which is rec.exact_time - now) to the cooldown duration would be doubling up any remaining portion of the cooldown.

Does that make sense?

commented
if i == 1 and rec.exact_time and rec.exact_time > now and start + duration < rec.exact_time then
    duration = rec.exact_time - start
end

This additional condition seems to prevent that issue. Will do more testing tonight.

commented

Hmm, your method actually has a weird interaction with clearcasting that doesn't show up on mine. The way I had it, clearcasting would immediately wipe the cooldown spiral from Shred and light up as ready with the shine border. Yours lights up and adds the shine border but doesn't cancel the cooldown spiral, it will keep going until it finishes.

Though it's possible that's a bug with the rec.exact_time not updating properly when clearcasting is gained (since the ability is now technically usable earlier than the original expected time). It's just something you'd never notice when used the old way.

EDIT: Other than that they behave identically as far as my eye can see.

commented

This is the new default behavior (Displays > X > Delays > Indicator Type: Cooldown Sweep) as of 8.1.5-11-beta2.