Bartender4-18.4, and hunter aspect flyout issue, wow forever #2451


Open
  • Sultonmrp created this issue Nov 8, 2026

    ok, when i click my hunters aspect flyout thing, it shows all ranks of my aspects, with bartender disabled, only shows the highest i currently know

    info from an AI.

    Bartender4 / LibActionButton: Forever flyout shows every spell rank
    ====================================================================

    For: Nevcairiel / Bartender4 + LibActionButton-1.0
    Addon: Bartender4 4.18.4 (Interface includes 16001)
    Lib: LibActionButton-1.0, MINOR_VERSION 168 (embedded)
    Client: WoW Forever / Camelot, GetBuildInfo() toc 16001
    Reporter: hunter, action-bar flyout id 253 (Aspects)

    This file is a bug report only. No Bartender files were patched.

     

    1. Symptom
    ----------

    On WoW Forever, a hunter Aspect flyout on a Bartender bar lists every learned
    rank of each Aspect (Hawk 1, Hawk 2, Hawk 3, ...).

    The same flyout on default Blizzard bars (Bartender disabled) lists only the
    highest / current rank of each Aspect.

    FlyoutID observed: 253
    GetActionInfo(slot) returns: "flyout", 253

     

    2. Expected vs actual
    ---------------------

    Expected (Blizzard SpellFlyout): one button per Aspect, current rank only.
    Actual (Bartender): one button per known rank in GetFlyoutSlotInfo.

    Not caused by other addons (FojjiCore Spell Ranks, EnhanceQoL, etc.). Those
    only read GetFlyoutSlotInfo; they do not populate the popup.

    Confirmed by disabling Bartender: ranks collapse immediately.

     

    3. Cause
    --------

    Bartender never opens the client SpellFlyout frame on Forever.

    LibActionButton hardcodes a custom secure flyout for every game flavor:

    libs/LibActionButton-1.0/LibActionButton-1.0.lua

    Line 46: WoWForever = (buildInfo >= 16001 and buildInfo < 20000)
    Line 54: WoWMainline = WoWMainlineStandard or WoWForever
    Line 60: Feat_UseCustomFlyout = true -- always on, no option
    Line 291: button:SetAttribute("LABUseCustomFlyout", Feat_UseCustomFlyout)

    Click path (secure OnClick wrap), same file ~517-526:

    if type == "flyout" and self:GetAttribute("LABUseCustomFlyout") then
    flyoutHandler:SetAttribute("flyoutParentHandle", self)
    flyoutHandler:RunAttribute("HandleFlyout", action)
    return false -- Blizzard SpellFlyout never runs
    end

    Custom handler: LABFlyoutHandlerFrame (GetFlyoutHandler, ~991+).
    Bartender4/Bar.lua ~416-419 only treats that frame as "the" flyout.

    Forever still stores every learned rank as isKnown on the flyout.
    Blizzard SpellFlyout collapses that list. LAB does not.

     

    4. Where LAB copies flyout slots
    --------------------------------

    DiscoverFlyoutSpells / UpdateFlyoutSpells
    libs/LibActionButton-1.0/LibActionButton-1.0.lua 1082-1132

    for flyoutID = 1, 300 do
    GetFlyoutInfo(flyoutID)
    for slotID = 1, numSlots do
    local spellID, overrideSpellID, isKnownSlot = GetFlyoutSlotInfo(flyoutID, slotID)

    -- ONLY extra filter: empty Call Pet slots
    local petIndex, petName = GetCallPetSpellInfo(spellID)
    if petIndex and (not petName or petName == "") then
    isKnownSlot = false
    end

    slots[slotID] = { spellID, overrideSpellID, isKnown = isKnownSlot }
    end
    end

    overrideSpellID is stored on the lua table and then unused.

    SyncFlyoutInfoToHandler ~1033-1038
    Restricted env gets only:
    LAB_FlyoutInfo[id].slots[n].spellID
    LAB_FlyoutInfo[id].slots[n].isKnown
    overrideSpellID is NOT copied into the secure snippet.

    HandleFlyout (secure attribute) ~812-819

    for slotID, slotInfo in ipairs(info.slots) do
    if slotInfo.isKnown then -- no rank collapse
    slotButton:SetAttribute("type", "spell")
    slotButton:SetAttribute("spell", slotInfo.spellID) -- old rank id
    end
    end

    Empty pet slots are the only hide rule. There is no:
    - spellID == overrideSpellID check
    - "highest rank per spell name" collapse
    - spec/slotSpecID filter from extra GetFlyoutSlotInfo returns

     

    5. Why default bars look correct
    --------------------------------

    Default bars use FrameXML SpellFlyout (not shipped in AddOns). With Bartender
    off, that popup shows current ranks only. Same GetFlyoutSlotInfo data, different
    renderer.

    LAB was written against retail flyouts where each slot is already one spell.
    Forever hunter (and likely other Classic-style) flyouts keep every rank known.

     

    6. How to reproduce
    -------------------

    1. WoW Forever hunter with several Aspect ranks learned.
    2. Place the Aspect flyout (id 253) on a Bartender bar.
    3. Open it: every rank appears.
    4. /disable Bartender4, /reload, open the same flyout on a default bar:
    only highest ranks.
    5. Dump (out of combat):

    /dump GetFlyoutInfo(253)
    /run for i=1,select(3,GetFlyoutInfo(253)) do print(i, GetFlyoutSlotInfo(253,i)) end

    Author should inspect overrideSpellID vs spellID, extra returns (name,
    slotSpecID), and whether superseded ranks still have isKnown == true.

     

    7. Suggested fix (LibActionButton, not Bartender UI)
    ----------------------------------------------------

    Do not turn Feat_UseCustomFlyout off on Forever as the first try. LAB buttons
    need the secure handler; handing them to SpellFlyout is why custom flyout exists.

    Preferred: collapse ranks when snapshotting, so the secure table is already
    correct.

    A) If Forever sets overrideSpellID to the current rank for every slot:

    After GetFlyoutSlotInfo:
    if overrideSpellID and overrideSpellID ~= 0 and overrideSpellID ~= spellID then
    isKnownSlot = false
    end

    That keeps only the slot whose spellID is the live rank.
    Apply in both DiscoverFlyoutSpells and UpdateFlyoutSpells.

    B) If overrideSpellID is nil/0 on Forever, collapse by spell name + rank
    (GetSpellSubtext / C_Spell.GetSpellSubtext) and keep the max rank per base
    name. Also skip duplicates of the same overrideSpellID.

    C) Optionally still copy overrideSpellID into LAB_FlyoutInfo in
    SyncFlyoutInfoToHandler (~1038) and cast overrideSpellID in HandleFlyout
    so the button always fires the current rank.

    D) If GetFlyoutSlotInfo returns slotSpecID, honor it the way SpellFlyout does
    (hide off-spec slots).

    Re-sync after SPELLS_CHANGED / LEARNED_SPELL_IN_SKILL_LINE (UpdateFlyoutSpells
    already exists; keep using it).

    Do not filter only in insecure OnShow: HandleFlyout is secure and reads the
    snapshot.

     

    8. Files / functions to touch
    -----------------------------

    libs/LibActionButton-1.0/LibActionButton-1.0.lua
    Feat_UseCustomFlyout ~60
    WrapOnClick flyout intercept ~517-526
    FlyoutHandleFunc ~787-860
    SyncFlyoutInfoToHandler ~1026-1078
    DiscoverFlyoutSpells ~1082-1103
    UpdateFlyoutSpells ~1106-1133

    Bartender4/Bar.lua ~416-419 (only mouseover/parent;
    does not build slots)

    Bartender4/GameTypes.lua Forever flag ~8, 16
    (no flyout logic here)

     

    9. Workaround for users until fixed
    -----------------------------------

    Disable Bartender and use default bars for that flyout, or place individual
    current-rank Aspect spells on the bar instead of flyout 253.

     

    10. Related notes
    -----------------

    LAB comment at DiscoverFlyoutSpells: "300 is a safe upper limit in 10.0.2,
    the highest known spell is 229". Forever already uses 253; the scan range is
    fine. The bug is slot filtering, not the ID cap.


To post a comment, please login or register a new account.