From cc5ae76036b64a1f1108d6a7a47bb9e9a9cf67e9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 6 Sep 2026 07:38:27 +0000 Subject: [PATCH] fix: refresh charged items on slot unlock --- .../workflows/fix-charge-unlock-refresh.yml | 63 ------------------- UI/BagFrame.lua | 51 ++++++++++++++- 2 files changed, 49 insertions(+), 65 deletions(-) delete mode 100644 .github/workflows/fix-charge-unlock-refresh.yml diff --git a/.github/workflows/fix-charge-unlock-refresh.yml b/.github/workflows/fix-charge-unlock-refresh.yml deleted file mode 100644 index 686b69c..0000000 --- a/.github/workflows/fix-charge-unlock-refresh.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Apply charge unlock refresh - -on: - push: - branches: - - refactor/consolidate-patch-layers - -permissions: - contents: write - -jobs: - patch: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: refactor/consolidate-patch-layers - fetch-depth: 0 - - - name: Refresh charge overlay when item unlocks - shell: python - run: | - from pathlib import Path - - p = Path('UI/BagFrame.lua') - t = p.read_text(encoding='utf-8') - - old = '''function BagFrame:RefreshKnownChargeOverlays(bagID)\n local detection = addon.Modules.ItemDetection\n if not detection or not detection.IsKnownChargeItem or not Guda_ItemButton_UpdateCharges then return end\n\n detection:InvalidateCharges(bagID)\n local buttons = slotToButton[bagID]\n if not buttons then return end\n\n for _, button in pairs(buttons) do\n if button and button.hasItem and button:IsShown()\n and detection:IsKnownChargeItem(button.itemData) then\n Guda_ItemButton_UpdateCharges(button)\n end\n end\nend\n''' - - new = '''function BagFrame:RefreshKnownChargeOverlays(bagID, slotID)\n local detection = addon.Modules.ItemDetection\n if not detection or not detection.IsKnownChargeItem or not Guda_ItemButton_UpdateCharges then return end\n\n local buttons = slotToButton[bagID]\n\n -- ITEM_LOCK_CHANGED gives us an exact slot. In that path, avoid touching\n -- any other item or negative charge-cache entry in the bag.\n if slotID then\n local button = buttons and (buttons[slotID] or buttons[tonumber(slotID)])\n if button and button.hasItem and button:IsShown()\n and detection:IsKnownChargeItem(button.itemData) then\n detection:InvalidateCharges(bagID, slotID)\n Guda_ItemButton_UpdateCharges(button)\n end\n return\n end\n\n detection:InvalidateCharges(bagID)\n if not buttons then return end\n\n for _, button in pairs(buttons) do\n if button and button.hasItem and button:IsShown()\n and detection:IsKnownChargeItem(button.itemData) then\n Guda_ItemButton_UpdateCharges(button)\n end\n end\nend\n''' - - if old not in t: - raise SystemExit('RefreshKnownChargeOverlays block not found') - t = t.replace(old, new, 1) - - old = ''' local bagUpdateFrame = CreateFrame("Frame")\n bagUpdateFrame:RegisterEvent("BAG_UPDATE")\n bagUpdateFrame:RegisterEvent("BAG_UPDATE_DELAYED")\n bagUpdateFrame:SetScript("OnEvent", function()\n -- ClassicAPI fires BAG_UPDATE_DELAYED at the tail of the world tick, after\n''' - - new = ''' local bagUpdateFrame = CreateFrame("Frame")\n bagUpdateFrame:RegisterEvent("BAG_UPDATE")\n bagUpdateFrame:RegisterEvent("BAG_UPDATE_DELAYED")\n bagUpdateFrame:RegisterEvent("ITEM_LOCK_CHANGED")\n bagUpdateFrame:SetScript("OnEvent", function()\n -- Charged consumables such as Wizard Oil can change their remaining\n -- charges without producing a useful BAG_UPDATE. ITEM_LOCK_CHANGED gives\n -- the exact bag/slot: wait for the unlock edge, then refresh that one\n -- already-known charge item on the following frame.\n if event == "ITEM_LOCK_CHANGED" then\n local lockBagID = tonumber(arg1)\n local lockSlotID = tonumber(arg2)\n if not lockBagID or not lockSlotID or lockBagID < 0 or lockBagID > 4 then return end\n\n local _, _, isLocked = GetContainerItemInfo(lockBagID, lockSlotID)\n if isLocked then return end\n\n local function RefreshUnlockedCharge()\n if currentViewChar then return end\n if not Guda_BagFrame or not Guda_BagFrame:IsShown() then\n -- No visible overlay to update; discard this slot's positive\n -- cache so the next render reads the live tooltip value.\n if addon.Modules.ItemDetection and addon.Modules.ItemDetection.InvalidateCharges then\n addon.Modules.ItemDetection:InvalidateCharges(lockBagID, lockSlotID)\n end\n return\n end\n BagFrame:RefreshKnownChargeOverlays(lockBagID, lockSlotID)\n end\n\n if Guda_ScheduleTimer then\n Guda_ScheduleTimer(0, RefreshUnlockedCharge)\n else\n RefreshUnlockedCharge()\n end\n return\n end\n\n -- ClassicAPI fires BAG_UPDATE_DELAYED at the tail of the world tick, after\n''' - - if old not in t: - raise SystemExit('bag event registration block not found') - t = t.replace(old, new, 1) - p.write_text(t, encoding='utf-8') - - Path('.github/workflows/fix-charge-unlock-refresh.yml').unlink() - - - name: Validate Lua - run: | - sudo apt-get update -qq - sudo apt-get install -y -qq lua5.1 - set -e - find . -name '*.lua' -print0 | while IFS= read -r -d '' f; do - luac5.1 -p "$f" - done - - - name: Commit patch - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git commit -m "fix: refresh charged items on slot unlock" - git push origin HEAD:refactor/consolidate-patch-layers diff --git a/UI/BagFrame.lua b/UI/BagFrame.lua index 0b1b07e..14137e2 100644 --- a/UI/BagFrame.lua +++ b/UI/BagFrame.lua @@ -4215,12 +4215,25 @@ end -- Refresh only known charge-bearing items in one changed bag. -- Normal stacks remain on the cached negative path and incur no tooltip scan. -function BagFrame:RefreshKnownChargeOverlays(bagID) +function BagFrame:RefreshKnownChargeOverlays(bagID, slotID) local detection = addon.Modules.ItemDetection if not detection or not detection.IsKnownChargeItem or not Guda_ItemButton_UpdateCharges then return end - detection:InvalidateCharges(bagID) local buttons = slotToButton[bagID] + + -- ITEM_LOCK_CHANGED gives us an exact slot. In that path, avoid touching + -- any other item or negative charge-cache entry in the bag. + if slotID then + local button = buttons and (buttons[slotID] or buttons[tonumber(slotID)]) + if button and button.hasItem and button:IsShown() + and detection:IsKnownChargeItem(button.itemData) then + detection:InvalidateCharges(bagID, slotID) + Guda_ItemButton_UpdateCharges(button) + end + return + end + + detection:InvalidateCharges(bagID) if not buttons then return end for _, button in pairs(buttons) do @@ -4328,7 +4341,41 @@ function BagFrame:Initialize() local bagUpdateFrame = CreateFrame("Frame") bagUpdateFrame:RegisterEvent("BAG_UPDATE") bagUpdateFrame:RegisterEvent("BAG_UPDATE_DELAYED") + bagUpdateFrame:RegisterEvent("ITEM_LOCK_CHANGED") bagUpdateFrame:SetScript("OnEvent", function() + -- Charged consumables such as Wizard Oil can change their remaining + -- charges without producing a useful BAG_UPDATE. ITEM_LOCK_CHANGED gives + -- the exact bag/slot: wait for the unlock edge, then refresh that one + -- already-known charge item on the following frame. + if event == "ITEM_LOCK_CHANGED" then + local lockBagID = tonumber(arg1) + local lockSlotID = tonumber(arg2) + if not lockBagID or not lockSlotID or lockBagID < 0 or lockBagID > 4 then return end + + local _, _, isLocked = GetContainerItemInfo(lockBagID, lockSlotID) + if isLocked then return end + + local function RefreshUnlockedCharge() + if currentViewChar then return end + if not Guda_BagFrame or not Guda_BagFrame:IsShown() then + -- No visible overlay to update; discard this slot's positive + -- cache so the next render reads the live tooltip value. + if addon.Modules.ItemDetection and addon.Modules.ItemDetection.InvalidateCharges then + addon.Modules.ItemDetection:InvalidateCharges(lockBagID, lockSlotID) + end + return + end + BagFrame:RefreshKnownChargeOverlays(lockBagID, lockSlotID) + end + + if Guda_ScheduleTimer then + Guda_ScheduleTimer(0, RefreshUnlockedCharge) + else + RefreshUnlockedCharge() + end + return + end + -- ClassicAPI fires BAG_UPDATE_DELAYED at the tail of the world tick, after -- all BAG_UPDATE events for that frame and after bag contents have settled. -- This is the correct point to rescan instance-only data such as charges.