WeakAuras / WeakAuras2

World of Warcraft addon that provides a powerful framework to display customizable graphics on your screen.
https://weakauras.wtf
GNU General Public License v2.0
1.31k stars 318 forks source link

GetTotemInfo vs GetTotemTimeLeft #5378

Closed mrbuds closed 2 months ago

mrbuds commented 2 months ago

Is there an existing issue for this?

Description

TotemFrame.lua use the function GetTotemTimeLeft to show remaining time Totem trigger use startTime + duration from GetTotemInfo

following aura show difference between these 2 when i drop a Earthbind Totem

!WA:2!1rvZUTTrq4iOdfGOiWrhCAt7bcx0azevKeJICOPPaMUsXUvXYLIUo9e7sUdf3KL7Uy3LYs5Oqrrp7R9Mo3Erpc5jGWOpb5ripbDwsfBdJyccWzw8nFZFFlBnOtrhAh6FTTwwA5mbOhDC0WdoSFyQKl1)uB8zfLzuCY8iyMDRVoDzAPXklCEZATrwPi1YKIUB75JpCzkH7t8FM)ZbBK0cfrScyiKz7(4gexbwCp3RXs0whQE(0snXr2vc)arM8dH2efmtXAG5ccHEbb(eb1V7LUp4cc32xQ9F0tVcljyGxlYl9(b)hvFY1s13uxvOv3g(QPtPzcBxsp)KT9ab9CtoHkp93gLLza7xERverAUuFKerLSx)dJ6hQ8VYanotQli2yvSfjETxl1gxoKpwrjwiPS(Z7iL4XyjLEcJAZd2fD1K6nG5jH1DGxsgtWm5Eb4hR3cRMnzcOn3((61M)5skYxww0CfO3V)WJgC8Wal6esW51olmkGZpGA8ENPmbMcc7yenB2Q492DCu84ODdJckrYtCDbOdfKcW4fwdnzFGWT5xe6rAadnC8r9ho8SsX6sWtDhxvpfIA8FHKc)ZTuBDZtMcjng3fWVRU)ndIdtiPZJZ4sPo)mdWZAg8bJIIg9IGmPWQ2yGM9g)FPKqr6i(rrQV4Jqy6AJaHuabCjHoiXs4ydTzyrj3Y8cWXu6Mvp0lmLtmgNvGH9gWzSWLPXOZNVwp8Yg9q7pAUuRncD9aDPgM4uC4(iWIOoJiyf1IWNuTXG3cedm2QbXeB(NuD3QEN)brESBfQnqQuqnlC4CCu1lOGWedQ(UA0vpT67REg(9ox)K3Jdkqli8FfjbP7VvF1npOvAiL5q1EPlDSAbONEwtB2kbpmJnXt)kugZYMhmS)GOLwz60gU)Sw)7QTy0Doeov9GBol05OYILgBZ1GjxYPZxLPrTg2)4QR97BUBnWDKRvtgVxy)(hQNVUk2PKrxPgAOV2(Z7)4N)TNJxEq8Junv7ItLA6jAIAXjRnw1SS2R(xFTA1Q9su6c06RA)XNUIjAkpmAVLO(oSErzU3Mv39C0nHK(6j4)rf0oMD(ryANP)3l)))

https://github.com/user-attachments/assets/907bcda5-adcd-4257-8058-05e6493162ba

function()
    local a = GetTotemTimeLeft(1)

    local _, _, startTime, duration = GetTotemInfo(1)
    local expirationTime = startTime and (startTime + duration) or 0;
    local b =  startTime and startTime > 0 and expirationTime - GetTime() or 0
    print(a, b)
end

When i drop totem, using data from GetTotemInfo timer start at 19.5379 instead of 20

Totem visually despawn when GetTotemTimeLeft reach 0

Problem is that GetTotemTimeLeft is only accurate when totem is casted, when checking later with a scheduled scan the data is not good enough

A solution could be to keep track of timers in GenericTrigger.lua, only update value when there was no totem or value is higher than calculated remaining time + gcd?

WeakAuras Version

dev

World of Warcraft Flavor

Retail (Default)

World of Warcraft Region

EU

Tested with only WeakAuras

I got this issue with only WeakAuras enabled

Lua Error

No response

Reproduction Steps

drop a Earthbind Totem on shaman

Last Good Version

No response

Screenshots

No response

Export String

No response

Bisector Report

No response

emptyrivers commented 2 months ago

There is also C_TooltipInfo.GetTotem, though it isn't that interesting: image

InfusOnWoW commented 2 months ago

So some totems do have secondary effects that can be tracked, e.g. I think there's a shielding totem, spirit link gives a buff etc. I'd would want to test how the timing of these match up to what the totem apis return.

GetTotemTimeLeft() is clearly some rounded value and assuming that on initial totem dropping the totem duration is exactly that rounded value seems a questionable assumption.

mrbuds commented 2 months ago

test with SLT

function()
    local a = GetTotemTimeLeft(1)

    local _, _, startTime, duration = GetTotemInfo(1)
    local expirationTime = startTime and (startTime + duration) or 0;
    local b =  startTime and startTime > 0 and expirationTime - GetTime() or 0

    local sltInfo = C_UnitAuras.GetPlayerAuraBySpellID(325174)
    local slt = sltInfo and true or false 
    print(a, b, slt)
end

https://github.com/user-attachments/assets/27144c8d-7ae2-48cc-a9c1-973af582c15b

image

buff is still active when timer from GetTotemInfo is negative

mrbuds commented 2 months ago

Buff is still active for a few frame after GetTotemTimeLeft return 0

InfusOnWoW commented 2 months ago

Oh boy what an output, the last line is: 0 -1.1138.. true

So the GetTotemInfo is off by a whole second.

InfusOnWoW commented 2 months ago

Lookng at the video again, at the start the difference is .96s, at the end of the video it's 1.11.

grafik

So this screenshot from the video shows the exact timestamp from when the duration jumps from 6 to 5 in GetTotemTimeLeft, which seems to indicate it's a simple "ceil".

I think our options are: a) Keep using the GetTotemInfo (verify that we show the totem as long as GetTotemInfo returns something, even if we get negative times) b) Get an initial time from GetTotemTimeLeft and assume that all totem duration are always integers at the start c) Sync via GetTotemTimeLeft, that is check every frame whether that switched and then sync to that

We should also complain to blizzard, that api stinks.

mrbuds commented 2 months ago

old

https://github.com/user-attachments/assets/f29cd1aa-148f-4299-b63e-726153e7f9d6

new

https://github.com/user-attachments/assets/7346631f-ee5a-4fc6-9113-48be9b2bc22a

using this

function Private.InitTotemTimer()
  print("InitTotemTimer")
  local totemInfo
  if not Private.ExecEnv.GetTotemTimer then
    totemInfo = {}

    function Private.ExecEnv.GetTotemTimer(totemSlot)
      local info = totemInfo[totemSlot]
      if info then
        print("GetTotemTimer", info.duration, info.startTime)
        return info.startTime, info.duration
      end
    end

    local totemTimerFrame = CreateFrame("Frame")

    -- run every frame until GetTotemTimeLeft has changed
    local function recheckTimers(self, elapsed)
      local stillrecheck = false
      local sendEvent
      for slot, info in pairs(totemInfo) do
        if info.recheck then
          local newTimeLeft = GetTotemTimeLeft(slot)
          if newTimeLeft ~= info.duration then
            info.duration = (GetTime() - info.startTime) + newTimeLeft
            print("duration2", info.duration, "exp", info.startTime + info.duration)
            info.recheck = false
            sendEvent = true
          else
            stillrecheck = true
          end
        end
      end
      if not stillrecheck then
        totemTimerFrame:SetScript("OnUpdate", nil)
      end
      if sendEvent then
        WeakAuras.ScanEvents("WA_TOTEM_UPDATE")
      end
    end

    local function OnEventScript(self, event, totemSlot)
      local timeLeft = GetTotemTimeLeft(totemSlot)
      print("duration1", timeLeft, "exp", GetTime() + timeLeft)
      totemInfo[totemSlot] = { duration = timeLeft, startTime = GetTime(), recheck = true }
      WeakAuras.ScanEvents("WA_TOTEM_UPDATE")
      totemTimerFrame:SetScript("OnUpdate", recheckTimers)
    end

    totemTimerFrame:RegisterEvent("PLAYER_TOTEM_UPDATE")
    totemTimerFrame:SetScript("OnEvent", OnEventScript)
  end
end
InfusOnWoW commented 2 months ago

I think totem slot numbers are not stable, that is a totem that is in slot X will when a totem with a lower slot number expires change it slot number. Though I might be misremembering. Probably worth testing

Can't demo warlocks summon multiple totems of the same type?

And historical, the first implementation of Gargoyle increased its duration each time the player used runic power. I'm not 100% certain it was an totem back then though. But class designers have used the totem api for lots of things, which behave in lots of ways...

Is this totem inaccuracy new with TWW? Or what triggered this investigation?

emptyrivers commented 2 months ago

Can't demo warlocks summon multiple totems of the same type?

Yes, it's even on a 1 min cd now so it's not quite so annoying to test with: Cast Call Dreadstalkers, then Summon Demonic Tyrant (extending all totem summons by 15 seconds), and then Call Dreadstalkers again.

Also, I believe restoration shamans can summon two Healing Stream Totems at once.

mrbuds commented 2 months ago

I can't tell if this inaccuracy is new, this discord thread caught my attention https://discord.com/channels/172440238717665280/1280310878096593058/1280310878096593058 and i was surprised to see the game wasn't using GetTotemInfo

You guys convinced me this is something wow's dev needs to solve, and we shouldn't try to work around it

Opened a ticket at https://github.com/Stanzilla/WoWUIBugs/issues/651