From 1f72b93ea5a7a420d7b7d6e799433e6b8e9578fd Mon Sep 17 00:00:00 2001 From: Meow <30401521+me0wg4ming@users.noreply.github.com> Date: Tue, 31 Mar 2026 07:11:48 +0200 Subject: [PATCH] New feature for "Buff" > "Target Debuff Bar" "Target Debuff Bar" should now correctly show only own debuffs (there will be still debuffs that are not shown up properly like AOE spells or procs) --- api/config.lua | 2 - libs/libdebuff.lua | 101 +++++++++++++++++++++++++++++++++++++----- modules/buffwatch.lua | 4 +- modules/gui.lua | 4 +- 4 files changed, 92 insertions(+), 19 deletions(-) diff --git a/api/config.lua b/api/config.lua index bd6d94ed..c1c81355 100644 --- a/api/config.lua +++ b/api/config.lua @@ -490,7 +490,6 @@ function pfUI:LoadConfig() pfUI:UpdateConfig("unitframes", unit, "debuffsize", "20") pfUI:UpdateConfig("unitframes", unit, "debufflimit", "32") pfUI:UpdateConfig("unitframes", unit, "debuffperrow", "8") - pfUI:UpdateConfig("unitframes", unit, "selfdebuff", "0") pfUI:UpdateConfig("unitframes", unit, "invert_healthbar", "0") pfUI:UpdateConfig("unitframes", unit, "verticalbar", "0") pfUI:UpdateConfig("unitframes", unit, "buff_indicator", "0") @@ -816,7 +815,6 @@ function pfUI:LoadConfig() pfUI:UpdateConfig("nameplates", nil, "showdebuffs", "1") pfUI:UpdateConfig("nameplates", nil, "showdebuffs_hostile", "1") pfUI:UpdateConfig("nameplates", nil, "showdebuffs_friendly", "0") - pfUI:UpdateConfig("nameplates", nil, "selfdebuff", "0") pfUI:UpdateConfig("nameplates", nil, "guessdebuffs", "1") pfUI:UpdateConfig("nameplates", nil, "clickthrough", "0") pfUI:UpdateConfig("nameplates", nil, "rightclick", "1") diff --git a/libs/libdebuff.lua b/libs/libdebuff.lua index b8e89893..1332bc7a 100644 --- a/libs/libdebuff.lua +++ b/libs/libdebuff.lua @@ -616,6 +616,22 @@ end local function CleanupOutOfRangeUnits() local now = GetTime() + -- Cleanup expired pending entries (every 1s) + if not pfUI.libdebuff_last_pending_cleanup then pfUI.libdebuff_last_pending_cleanup = 0 end + if now - pfUI.libdebuff_last_pending_cleanup >= 1 then + pfUI.libdebuff_last_pending_cleanup = now + for guid, spells in pairs(ownDebuffs) do + for spellName, data in pairs(spells) do + if data.pending then + local timeleft = (data.startTime + data.duration) - now + if timeleft < -2 then + spells[spellName] = nil + end + end + end + end + end + if now - lastRangeCheck < 10 then return end lastRangeCheck = now @@ -959,15 +975,29 @@ function libdebuff:UnitOwnDebuff(unit, id) local sortedDebuffs = {} local now = GetTime() + local toRemove = nil for spellName, data in pairs(ownDebuffs[guid]) do local timeleft = (data.startTime + data.duration) - now - if timeleft > -1 then -- Grace period + if timeleft > 0 then local count = table.getn(sortedDebuffs) + 1 sortedDebuffs[count] = { spellName = spellName, data = data, timeleft = timeleft } + elseif data.pending then + if timeleft < -2 then + toRemove = toRemove or {} + toRemove[spellName] = true + end + else + toRemove = toRemove or {} + toRemove[spellName] = true + end + end + if toRemove then + for spellName in pairs(toRemove) do + ownDebuffs[guid][spellName] = nil end end @@ -1111,29 +1141,41 @@ if hasNampower then local refreshTime = GetTime() local myGuid = GetPlayerGUID() - -- Refresh in ownDebuffs + -- Refresh in ownDebuffs - only if timer still active if ownDebuffs[guid] then if ownDebuffs[guid]["Rip"] then - ownDebuffs[guid]["Rip"].startTime = refreshTime - if debugStats.enabled then - DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff[CARNAGE]|r Rip refreshed (CP detected)") + local timeleft = (ownDebuffs[guid]["Rip"].startTime + ownDebuffs[guid]["Rip"].duration) - refreshTime + if timeleft > 0 then + ownDebuffs[guid]["Rip"].startTime = refreshTime + if debugStats.enabled then + DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff[CARNAGE]|r Rip refreshed (CP detected)") + end end end if ownDebuffs[guid]["Rake"] then - ownDebuffs[guid]["Rake"].startTime = refreshTime - if debugStats.enabled then - DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff[CARNAGE]|r Rake refreshed (CP detected)") + local timeleft = (ownDebuffs[guid]["Rake"].startTime + ownDebuffs[guid]["Rake"].duration) - refreshTime + if timeleft > 0 then + ownDebuffs[guid]["Rake"].startTime = refreshTime + if debugStats.enabled then + DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff[CARNAGE]|r Rake refreshed (CP detected)") + end end end end - -- Refresh in allAuraCasts + -- Refresh in allAuraCasts - only if timer still active if allAuraCasts[guid] then if allAuraCasts[guid]["Rip"] and allAuraCasts[guid]["Rip"][myGuid] then - allAuraCasts[guid]["Rip"][myGuid].startTime = refreshTime + local d = allAuraCasts[guid]["Rip"][myGuid] + if (d.startTime + d.duration) > refreshTime then + d.startTime = refreshTime + end end if allAuraCasts[guid]["Rake"] and allAuraCasts[guid]["Rake"][myGuid] then - allAuraCasts[guid]["Rake"][myGuid].startTime = refreshTime + local d = allAuraCasts[guid]["Rake"][myGuid] + if (d.startTime + d.duration) > refreshTime then + d.startTime = refreshTime + end end end @@ -1316,7 +1358,7 @@ if hasNampower then if numMissed > 0 or numHit == 0 then return end local spellName = GetSpellRecField and GetSpellRecField(spellId, "name") - local spellRankString + local spellRankString = GetSpellRecField and GetSpellRecField(spellId, "rank") if not spellName then return end local castRank = 0 @@ -1333,6 +1375,41 @@ if hasNampower then time = GetTime() } end + + -- selfdebuff mode: write ownDebuffs immediately on confirmed hit + -- so buffwatch shows our debuffs even when over the 16 debuff cap + if event == "SPELL_GO_SELF" and targetGuid and not isNullTarget then + local selfdebuffMode = pfUI_config and pfUI_config.buffbar and + pfUI_config.buffbar.tdebuff and pfUI_config.buffbar.tdebuff.selfdebuff == "1" + if selfdebuffMode then + local myGuid2 = GetPlayerGUID() + if casterGuid == myGuid2 then + local duration = libdebuff:GetDuration(spellName, castRank) or 0 + if duration > 0 then + local texture = libdebuff:GetSpellIcon(spellId) + ownDebuffs[targetGuid] = ownDebuffs[targetGuid] or {} + -- Downrank protection + local existing = ownDebuffs[targetGuid][spellName] + local blocked = false + if existing and existing.rank and castRank > 0 and existing.rank > castRank then + local existingTimeleft = (existing.startTime + existing.duration) - GetTime() + if existingTimeleft > 0 then blocked = true end + end + if not blocked then + ownDebuffs[targetGuid][spellName] = { + startTime = GetTime(), + duration = duration, + texture = texture, + rank = castRank, + spellId = spellId, + stacks = 1, + pending = true, + } + end + end + end + end + end -- Store rank for our casts local myGuid = GetPlayerGUID() diff --git a/modules/buffwatch.lua b/modules/buffwatch.lua index 8d83e1c1..8a42c805 100644 --- a/modules/buffwatch.lua +++ b/modules/buffwatch.lua @@ -280,8 +280,8 @@ pfUI:RegisterModule("buffwatch", "vanilla:tbc", function () -- For player: no slot in uuid (slots shift when other buffs expire) -- For target: include slot (multiple players can have same debuff, slot identifies who) local uuid - if frame.unit == "player" then - uuid = data[4] .. data[3] -- texture + name only + if frame.unit == "player" or (frame.config and frame.config.selfdebuff == "1") then + uuid = data[4] .. data[3] -- texture + name only (stable in selfdebuff mode) else uuid = data[4] .. data[3] .. data[2] -- texture + name + slot end diff --git a/modules/gui.lua b/modules/gui.lua index 0a3df233..11ab9529 100644 --- a/modules/gui.lua +++ b/modules/gui.lua @@ -2341,7 +2341,6 @@ pfUI:RegisterModule("gui", "vanilla:tbc", function () CreateConfig(U[c], T["Debuffs Per Row"], C.unitframes[c], "debuffperrow") if c ~= "player" then - CreateConfig(U[c], T["Only Show Own Debuffs (|cffffaaaaExperimental|r)"], C.unitframes[c], "selfdebuff", "checkbox") end CreateConfig(U[c], T["Combat/Aggro Indicators"], nil, nil, "header") @@ -2526,7 +2525,7 @@ pfUI:RegisterModule("gui", "vanilla:tbc", function () CreateConfig(nil, T["Color Debuff Stacks"], C.buffbar.tdebuff, "colorstacks", "checkbox") CreateConfig(nil, T["Buffbar Width"], C.buffbar.tdebuff, "width") CreateConfig(nil, T["Buffbar Height"], C.buffbar.tdebuff, "height") - CreateConfig(nil, T["Only Show Own Debuffs (|cffffaaaaExperimental|r)"], C.buffbar.tdebuff, "selfdebuff", "checkbox") + CreateConfig(nil, T["Show Only Own Debuffs"], C.buffbar.tdebuff, "selfdebuff", "checkbox") CreateConfig(nil, T["Filter Mode"], C.buffbar.tdebuff, "filter", "dropdown", pfUI.gui.dropdowns.buffbarfilter) CreateConfig(nil, T["Time Threshold"], C.buffbar.tdebuff, "threshold") CreateConfig(nil, T["Whitelist"], C.buffbar.tdebuff, "whitelist", "list") @@ -2906,7 +2905,6 @@ pfUI:RegisterModule("gui", "vanilla:tbc", function () CreateConfig(U["nameplates"], T["Show Timer Text"], C.nameplates, "debufftext", "checkbox") CreateConfig(Reload, T["Show Timer Animation"], C.nameplates, "debuffanim", "checkbox") - CreateConfig(U["nameplates"], T["Only Show Own Debuffs (|cffffaaaaExperimental|r)"], C.nameplates, "selfdebuff", "checkbox") CreateConfig(U["nameplates"], T["Filter Mode"], C.nameplates.debuffs, "filter", "dropdown", pfUI.gui.dropdowns.buffbarfilter) CreateConfig(U["nameplates"], T["Blacklist"], C.nameplates.debuffs, "blacklist", "list") CreateConfig(U["nameplates"], T["Whitelist"], C.nameplates.debuffs, "whitelist", "list")