mirror of
https://github.com/brues-code/SuperCleveRoidMacros.git
synced 2026-09-16 03:38:00 +00:00
update for pfui buff tracking and nampower buff tracking fallback
This commit is contained in:
+130
-11
@@ -877,9 +877,9 @@ CleveRoids.AuraCapStatus = {
|
||||
}
|
||||
|
||||
-- Overflow buff tracking: buffs applied while buff-capped (v2.34+)
|
||||
-- The server maintains up to 48 buff slots (32 visible + 16 invisible overflow).
|
||||
-- Buffs in slots 33-48 are mechanically active but have no client aura slot,
|
||||
-- so GetPlayerBuff/GetPlayerAuraDuration can't see them.
|
||||
-- GetUnitField "aura" returns 48 slots: [1-32] = buff slots, [33-48] = debuff slots.
|
||||
-- Beyond these 48 client slots, the server can hold additional overflow buffs with
|
||||
-- no aura slot at all -- invisible to GetPlayerBuff and GetPlayerAuraDuration.
|
||||
-- Populated from AURA_CAST_ON_SELF when auraCapStatus indicates buff bar full.
|
||||
-- Format: [spellId] = { timestamp = GetTime(), durationSec = durationMs/1000 }
|
||||
CleveRoids.OverflowBuffs = {}
|
||||
@@ -1036,12 +1036,10 @@ local function OnAuraCastSelf(spellId, casterGuid, targetGuid, effect, effectAur
|
||||
-- Check debuff bar full (bit 2)
|
||||
CleveRoids.AuraCapStatus.playerDebuffCapped = HasHitFlag(auraCapStatus, AURA_CAP_DEBUFF_FULL)
|
||||
|
||||
-- Track overflow buffs: if buff bar is full, this aura may land in server slots 33-48
|
||||
-- (no client aura slot). Store spellId + duration so /cancelaura and [mybuff] can find it.
|
||||
-- But first verify it's actually a buff — debuffs applied while buff-capped go into
|
||||
-- debuff slots (32-47), not buff overflow. Player debuffs never overflow into buff slots.
|
||||
if buffCapped and spellId and spellId > 0 and effectAuraName and effectAuraName > 0 then
|
||||
-- Check debuff slots (32-47) — if the spellId is there, it's a debuff, not overflow
|
||||
-- Determine if this aura is a buff (not debuff) — debuffs land in GetPlayerAuraDuration
|
||||
-- slots 32-47, so checking those slots identifies them regardless of cap status.
|
||||
local isBuffNotDebuff = false
|
||||
if spellId and spellId > 0 and effectAuraName and effectAuraName > 0 then
|
||||
local isDebuff = false
|
||||
if _G.GetPlayerAuraDuration then
|
||||
for slot = 32, 47 do
|
||||
@@ -1052,8 +1050,11 @@ local function OnAuraCastSelf(spellId, casterGuid, targetGuid, effect, effectAur
|
||||
end
|
||||
end
|
||||
end
|
||||
isBuffNotDebuff = not isDebuff
|
||||
|
||||
if not isDebuff then
|
||||
-- Track overflow buffs: if buff bar is full, this buff has no client aura slot.
|
||||
-- Store spellId + duration so /cancelaura and [mybuff] can find it.
|
||||
if buffCapped and isBuffNotDebuff then
|
||||
local entry = CleveRoids.OverflowBuffs[spellId]
|
||||
if not entry then
|
||||
entry = {}
|
||||
@@ -1062,7 +1063,9 @@ local function OnAuraCastSelf(spellId, casterGuid, targetGuid, effect, effectAur
|
||||
entry.timestamp = now
|
||||
entry.durationSec = durationMs and (durationMs / 1000) or 0
|
||||
end
|
||||
elseif not buffCapped and next(CleveRoids.OverflowBuffs) then
|
||||
end
|
||||
|
||||
if not buffCapped and next(CleveRoids.OverflowBuffs) then
|
||||
-- No longer buff-capped: some overflow buffs may have gotten real slots.
|
||||
-- Only remove entries that now appear in a visible aura slot.
|
||||
-- The server does NOT auto-migrate overflow buffs into freed slots,
|
||||
@@ -1091,6 +1094,33 @@ local function OnAuraCastSelf(spellId, casterGuid, targetGuid, effect, effectAur
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- NEW: Populate ownBuffCasts and allBuffAuras for all player buffs (not just overflow)
|
||||
-- Use the isBuffNotDebuff result determined above (avoids redundant slot scanning)
|
||||
local lib = CleveRoids.libdebuff
|
||||
if isBuffNotDebuff and spellId and durationMs and durationMs > 0 and lib and not lib.hasPfUIEnhanced then
|
||||
local spellName = SpellInfo and SpellInfo(spellId)
|
||||
if spellName then
|
||||
local _, playerGuidRaw = UnitExists("player")
|
||||
local playerGuid = playerGuidRaw and CleveRoids.NormalizeGUID(playerGuidRaw)
|
||||
if playerGuid then
|
||||
lib.ownBuffCasts[playerGuid] = lib.ownBuffCasts[playerGuid] or {}
|
||||
lib.ownBuffCasts[playerGuid][spellName] = {
|
||||
startTime = now,
|
||||
duration = durationMs / 1000,
|
||||
spellId = spellId,
|
||||
casterGuid = casterGuid,
|
||||
}
|
||||
lib.allBuffAuras[playerGuid] = lib.allBuffAuras[playerGuid] or {}
|
||||
lib.allBuffAuras[playerGuid][spellName] = lib.allBuffAuras[playerGuid][spellName] or {}
|
||||
lib.allBuffAuras[playerGuid][spellName][casterGuid or "unknown"] = {
|
||||
startTime = now,
|
||||
duration = durationMs / 1000,
|
||||
rank = 0,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function OnAuraCastOther(spellId, casterGuid, targetGuid, effect, effectAuraName,
|
||||
@@ -1126,6 +1156,25 @@ local function OnAuraCastOther(spellId, casterGuid, targetGuid, effect, effectAu
|
||||
spellName, spellId, string.sub(tostring(targetGuid), 1, 16), durationMs / 1000
|
||||
))
|
||||
end
|
||||
|
||||
-- NEW: Store in pendingBuffCasts for BUFF_ADDED_OTHER to confirm as buff
|
||||
-- (AURA_CAST_ON_OTHER fires for both buffs and debuffs; BUFF_ADDED_OTHER confirms buff)
|
||||
local lib = CleveRoids.libdebuff
|
||||
if lib and not lib.hasPfUIEnhanced then
|
||||
local spellNameForPending = SpellInfo and SpellInfo(spellId)
|
||||
if spellNameForPending then
|
||||
local normTargetGuid = CleveRoids.NormalizeGUID(targetGuid)
|
||||
if normTargetGuid then
|
||||
lib.pendingBuffCasts[normTargetGuid] = lib.pendingBuffCasts[normTargetGuid] or {}
|
||||
lib.pendingBuffCasts[normTargetGuid][spellId] = {
|
||||
casterGuid = CleveRoids.NormalizeGUID(casterGuid),
|
||||
duration = durationMs / 1000,
|
||||
spellName = spellNameForPending,
|
||||
time = now,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Store cap status for this target GUID (if available)
|
||||
@@ -3464,6 +3513,36 @@ function CleveRoids.ValidateAura(unit, args, isbuff)
|
||||
end
|
||||
end
|
||||
|
||||
-- allBuffAuras fallback for player buff timing: when slow path found the buff but
|
||||
-- returned no remaining time, check lib.allBuffAuras for cached AURA_CAST timing.
|
||||
if found and remaining == nil and isPlayer and isbuff and searchName then
|
||||
local lib = type(CleveRoids.libdebuff) == "table" and CleveRoids.libdebuff or nil
|
||||
if lib and lib.allBuffAuras then
|
||||
local _, playerGuidRaw = UnitExists("player")
|
||||
local playerGuid = CleveRoids.NormalizeGUID(playerGuidRaw)
|
||||
if playerGuid and lib.allBuffAuras[playerGuid] then
|
||||
-- Try exact name match first
|
||||
local casters = lib.allBuffAuras[playerGuid][args.name]
|
||||
-- Try lowercase match if exact didn't work
|
||||
if not casters then
|
||||
for bName, c in pairs(lib.allBuffAuras[playerGuid]) do
|
||||
if _string_lower(bName) == searchName then
|
||||
casters = c
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if casters then
|
||||
for _, cData in pairs(casters) do
|
||||
local elapsed = GetTime() - (cData.startTime or 0)
|
||||
remaining = cData.duration > 0 and (cData.duration - elapsed) or -1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Non-player overflow fallback: buff exists in server slots 33-48 (no client slot)
|
||||
-- AllCasterAuraTracking already has data from AURA_CAST_ON_OTHER for all aura applications.
|
||||
-- If the normal scan didn't find the buff, check there for presence + duration.
|
||||
@@ -3517,6 +3596,46 @@ function CleveRoids.ValidateAura(unit, args, isbuff)
|
||||
-- (showing ~1000s instead of actual remaining time). Skip it for buff time checks
|
||||
-- and rely on all-caster tracking from AURA_CAST events instead.
|
||||
|
||||
-- Fast path: Check lib.allBuffAuras (spellName-indexed, O(1) lookup)
|
||||
-- More efficient than FindAllCasterAuraByName which does ID→name translation
|
||||
if nonPlayerAuraTimeRemaining == nil and isbuff then
|
||||
local lib = type(CleveRoids.libdebuff) == "table" and CleveRoids.libdebuff or nil
|
||||
if lib and lib.allBuffAuras then
|
||||
local _, targetGuid = UnitExists(unit)
|
||||
targetGuid = targetGuid and CleveRoids.NormalizeGUID(targetGuid)
|
||||
if targetGuid then
|
||||
local buffEntries = lib.allBuffAuras[targetGuid]
|
||||
if buffEntries then
|
||||
-- Try exact name match first
|
||||
local casters = buffEntries[args.name]
|
||||
-- Try lowercase match if exact didn't work
|
||||
if not casters and searchName then
|
||||
for bName, c in pairs(buffEntries) do
|
||||
if _string_lower(bName) == searchName then
|
||||
casters = c
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if casters then
|
||||
for _, cData in pairs(casters) do
|
||||
local elapsed = GetTime() - (cData.startTime or 0)
|
||||
local rem = cData.duration > 0 and (cData.duration - elapsed) or -1
|
||||
if rem == nil or rem > 0 or cData.duration <= 0 then
|
||||
nonPlayerAuraTimeRemaining = rem
|
||||
if not found then
|
||||
found = true
|
||||
stacks = 0
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Second try: All-caster tracking from AURA_CAST events (works for any caster)
|
||||
-- Only use if libdebuff didn't find it (libdebuff has more accurate timing for player casts)
|
||||
if nonPlayerAuraTimeRemaining == nil then
|
||||
|
||||
@@ -2370,7 +2370,7 @@ function CleveRoids.DoWithConditionals(msg, hook, fixEmptyTargetFunc, targetBefo
|
||||
conditionals.target = origTarget
|
||||
return false
|
||||
end
|
||||
-- Set target to the found GUID for soft-casting via SuperWoW
|
||||
-- Set target to the found GUID for soft-casting via SuperWoW or Nampower v2.37+
|
||||
conditionals.target = scanResult
|
||||
-- Don't need to retarget since we're using GUID directly
|
||||
needRetarget = false
|
||||
@@ -2402,7 +2402,7 @@ function CleveRoids.DoWithConditionals(msg, hook, fixEmptyTargetFunc, targetBefo
|
||||
end
|
||||
end
|
||||
|
||||
if conditionals.target ~= nil and targetBeforeAction and not (CleveRoids.hasSuperwow and action == CastSpellByName) then
|
||||
if conditionals.target ~= nil and targetBeforeAction and not (action == CastSpellByName and (CleveRoids.hasSuperwow or CleveRoids.hasCastSpellByNameUnitToken)) then
|
||||
if not UnitIsUnit("target", conditionals.target) then
|
||||
if SpellIsTargeting() then
|
||||
SpellStopCasting()
|
||||
@@ -2501,7 +2501,7 @@ function CleveRoids.DoWithConditionals(msg, hook, fixEmptyTargetFunc, targetBefo
|
||||
-- Legacy path: !Attack without explicit conditionals (checkchanneled injected)
|
||||
if msg == CleveRoids.Localized.Attack and conditionals.checkchanneled then
|
||||
AttackTarget()
|
||||
elseif CleveRoids.hasSuperwow and conditionals.target then
|
||||
elseif (CleveRoids.hasSuperwow or CleveRoids.hasCastSpellByNameUnitToken) and conditionals.target then
|
||||
-- Let Nampower DLL handle queuing natively via its CastSpellByName hook
|
||||
CastSpellByName(castMsg, conditionals.target)
|
||||
else
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
--[[
|
||||
OverflowBuffFrame Extension
|
||||
Two frames displaying overflow buffs (slots 33-48) for the player
|
||||
and the current target (if a group/party member).
|
||||
Two frames displaying server-side overflow buffs (no client aura slot) for
|
||||
the player and the current target (if a group/party member).
|
||||
Player data: CleveRoids.OverflowBuffs (AURA_CAST_ON_SELF when buff-capped).
|
||||
Target data: CleveRoids.AllCasterAuraTracking filtered by UnitBuff visibility.
|
||||
Each frame shows 2 rows of 8 icons = 16 slots.
|
||||
|
||||
Author: Mewtiny
|
||||
@@ -98,7 +100,7 @@ local function CreateIconButton(parent, index, iconTable)
|
||||
if data.source ~= "player" then return end
|
||||
|
||||
-- CancelPlayerAuraSpellId(spellId, ignoreMissing)
|
||||
-- ignoreMissing=1 is required for overflow buffs in invisible slots 33-48
|
||||
-- ignoreMissing=1 is required for overflow buffs that have no client aura slot
|
||||
if CancelPlayerAuraSpellId then
|
||||
CancelPlayerAuraSpellId(data.spellId, 1)
|
||||
end
|
||||
|
||||
@@ -324,6 +324,8 @@ initFrame:SetScript("OnEvent", function()
|
||||
CleveRoids.hasGetUnitData = API.features.hasGetUnitData
|
||||
CleveRoids.hasGetSpellModifiers = API.features.hasGetSpellModifiers
|
||||
CleveRoids.hasEnhancedSpellFunctions = API.features.hasEnhancedSpellFunctions
|
||||
-- v2.37+: CastSpellByName supports unit token strings as 2nd param
|
||||
CleveRoids.hasCastSpellByNameUnitToken = API.features.hasCastSpellByNameUnitToken
|
||||
end
|
||||
|
||||
-- Initialize the API
|
||||
|
||||
+18
-3
@@ -88,8 +88,8 @@
|
||||
Aura Cancel Functions (v2.34+):
|
||||
- CancelPlayerAuraSlot(auraSlot) - Cancel buff/debuff by raw 0-based aura slot
|
||||
- CancelPlayerAuraSpellId(spellId, [ignoreMissing]) - Cancel buff/debuff by spell ID
|
||||
Pass ignoreMissing=1 to skip aura-slot presence check (for overflow buffs in
|
||||
server slots 33-48 that have no client aura slot)
|
||||
Pass ignoreMissing=1 to skip aura-slot presence check (for server-side
|
||||
overflow buffs that have no client aura slot in the 48-slot array)
|
||||
|
||||
GUID String Fix & Talent Helper (v2.35+):
|
||||
- GetUnitData/GetUnitField now return GUID-type fields (charm, summon, charmedBy,
|
||||
@@ -102,7 +102,14 @@
|
||||
- PlayerIsRooted() - Returns 1 if player is rooted, nil if not
|
||||
- PlayerIsSwimming() - Returns 1 if player is swimming, nil if not
|
||||
|
||||
Current version: v2.36.0
|
||||
Unit Token Cast & Mouseover (v2.37+):
|
||||
- CastSpellByName(spellName, unitToken) - 2nd param now accepts unit token strings
|
||||
(e.g. "mouseover", "party1", "focus") in addition to GUIDs and 1 (self).
|
||||
Enables soft-casting on unit tokens without changing the player's visible target.
|
||||
- SetMouseoverUnit(unitToken) - Programmatically set the mouseover unit.
|
||||
Previously only available via SuperWoW; now also provided by Nampower.
|
||||
|
||||
Current version: v2.37.0
|
||||
]]
|
||||
|
||||
local _G = _G or getfenv(0)
|
||||
@@ -272,6 +279,10 @@ API.VERSION_REQUIREMENTS = {
|
||||
["PlayerIsMoving"] = { 2, 36, 0, "PlayerIsMoving" },
|
||||
["PlayerIsRooted"] = { 2, 36, 0, "PlayerIsRooted" },
|
||||
["PlayerIsSwimming"] = { 2, 36, 0, "PlayerIsSwimming" },
|
||||
|
||||
-- v2.37+ - Unit token cast support and SetMouseoverUnit
|
||||
["CastSpellByNameUnitToken"]= { 2, 37, 0 }, -- CastSpellByName accepts unit token strings as 2nd param
|
||||
["SetMouseoverUnit"] = { 2, 37, 0, "SetMouseoverUnit" },
|
||||
}
|
||||
|
||||
-- Check if a specific feature is available
|
||||
@@ -425,6 +436,10 @@ local function InitializeFeatures()
|
||||
f.hasPlayerIsRooted = API.HasFeature("PlayerIsRooted")
|
||||
f.hasPlayerIsSwimming = API.HasFeature("PlayerIsSwimming")
|
||||
|
||||
-- v2.37+ Unit token cast support and SetMouseoverUnit
|
||||
f.hasCastSpellByNameUnitToken = API.HasFeature("CastSpellByNameUnitToken")
|
||||
f.hasSetMouseoverUnit = API.HasFeature("SetMouseoverUnit")
|
||||
|
||||
-- Runtime detection for enhanced spell functions (verify by testing)
|
||||
if f.hasEnhancedSpellFunctions and GetSpellTexture then
|
||||
local success, result = pcall(function()
|
||||
|
||||
+208
-8
@@ -328,7 +328,8 @@ do
|
||||
local isUpdatingMouseover = false
|
||||
|
||||
local function apply(unit)
|
||||
if CleveRoids.hasSuperwow and _G.SetMouseoverUnit then
|
||||
if _G.SetMouseoverUnit then
|
||||
-- Available via SuperWoW or Nampower v2.37+
|
||||
-- Set flag so UPDATE_MOUSEOVER_UNIT handler knows we triggered this
|
||||
CleveRoids.__mo.selfTriggered = true
|
||||
-- Use empty string instead of nil to properly clear mouseover.
|
||||
@@ -658,7 +659,7 @@ lib.guidToName = lib.guidToName or {}
|
||||
-- duration calculation, and miss/dodge/parry/resist/immune detection.
|
||||
|
||||
-- Enhanced tables (populated by pfUI or standalone Nampower handlers)
|
||||
lib.ownDebuffs = lib.ownDebuffs or {} -- [targetGUID][spellName] = {startTime, duration, texture, rank, slot}
|
||||
lib.ownDebuffs = lib.ownDebuffs or {} -- [targetGUID][spellName] = {startTime, duration, texture, rank, spellId}
|
||||
lib.ownSlots = lib.ownSlots or {} -- [targetGUID][slot] = spellName (LEGACY - empty when pfUI 7.6+ is active)
|
||||
lib.allSlots = lib.allSlots or {} -- [targetGUID][slot] = {spellName, casterGuid, isOurs} (LEGACY - empty when pfUI 7.6+ is active)
|
||||
lib.slotOwnership = lib.slotOwnership or {} -- [targetGUID][auraSlot] = {casterGuid, spellName, spellId, isOurs} (pfUI 7.6+ GetUnitField edition)
|
||||
@@ -667,6 +668,16 @@ lib.pendingCasts = lib.pendingCasts or {} -- [targetGUID][spellName] = {caster
|
||||
lib.recentMisses = lib.recentMisses or {} -- [targetGUID][spellName] = {time, spellId, targetName, reason} for miss/dodge/parry detection
|
||||
lib.iconCache = lib.iconCache or {} -- [spellId] = texture (shared with pfUI 7.6 or standalone)
|
||||
|
||||
-- Buff tracking tables (parallel to debuff tables, standalone Nampower mode only)
|
||||
-- Buff tables are NOT linked to pfUI — pfUI has no public buff tracking tables.
|
||||
-- They remain empty when hasPfUIEnhanced=true since all buff event handlers are gated by it.
|
||||
lib.ownBuffCasts = lib.ownBuffCasts or {} -- [targetGUID][buffName] = {startTime, duration, spellId, casterGuid}
|
||||
-- Player's own buff casts on self or others (AURA_CAST events)
|
||||
lib.allBuffAuras = lib.allBuffAuras or {} -- [targetGUID][buffName][casterGuid] = {startTime, duration, rank}
|
||||
-- All buffs from all casters on any unit (confirmed by BUFF_ADDED events)
|
||||
lib.pendingBuffCasts = lib.pendingBuffCasts or {} -- [targetGUID][spellId] = {casterGuid, duration, spellName, time}
|
||||
-- Temp storage from AURA_CAST_ON_OTHER, consumed by BUFF_ADDED_OTHER
|
||||
|
||||
-- Flag indicating whether enhanced pfUI tracking is available
|
||||
lib.hasPfUIEnhanced = false
|
||||
lib.hasStandaloneNampower = false
|
||||
@@ -702,7 +713,7 @@ function lib:HasEnhancedPfUILibdebuff()
|
||||
end
|
||||
|
||||
-- Verify Nampower version based on pfUI version:
|
||||
-- - pfUI 7.6+ (GetUnitField edition): requires Nampower v2.31.0+
|
||||
-- - pfUI 7.6+ (GetUnitField edition): requires Nampower v2.37.0+
|
||||
-- - pfUI 7.4.3 to 7.5.x (legacy): requires Nampower v2.26+
|
||||
if not GetNampowerVersion then return false end
|
||||
local npMajor, npMinor, npPatch = GetNampowerVersion()
|
||||
@@ -712,9 +723,9 @@ function lib:HasEnhancedPfUILibdebuff()
|
||||
local isPfUI76 = pfUI.libdebuff_slot_ownership ~= nil
|
||||
|
||||
if isPfUI76 then
|
||||
-- pfUI 7.6+ requires Nampower v2.31.0+
|
||||
-- pfUI 7.6+ requires Nampower v2.37.0+
|
||||
if npMajor < 2 then return false end
|
||||
if npMajor == 2 and npMinor < 31 then return false end
|
||||
if npMajor == 2 and npMinor < 37 then return false end
|
||||
else
|
||||
-- Legacy pfUI 7.4.3-7.5.x requires Nampower v2.26+
|
||||
if npMajor < 2 or (npMajor == 2 and npMinor < 26) then return false end
|
||||
@@ -732,7 +743,7 @@ function lib:HasEnhancedPfUILibdebuff()
|
||||
end
|
||||
|
||||
-- Check if pfUI v7.6+ with enhanced cast tracking is available
|
||||
-- pfUI 7.6 requires Nampower v2.31.0+ and exposes additional tables
|
||||
-- pfUI 7.6+ requires Nampower v2.37.0+ and exposes additional tables
|
||||
function lib:HasPfUI76()
|
||||
if not pfUI then return false end
|
||||
|
||||
@@ -743,12 +754,12 @@ function lib:HasPfUI76()
|
||||
if v.major < 7 then return false end
|
||||
if v.major == 7 and (v.minor or 0) < 6 then return false end
|
||||
|
||||
-- Verify Nampower v2.31.0+ (pfUI 7.6 hard requirement)
|
||||
-- Verify Nampower v2.37.0+ (pfUI 7.6+ hard requirement)
|
||||
if not GetNampowerVersion then return false end
|
||||
local npMajor, npMinor, npPatch = GetNampowerVersion()
|
||||
npPatch = npPatch or 0
|
||||
if npMajor < 2 then return false end
|
||||
if npMajor == 2 and npMinor < 31 then return false end
|
||||
if npMajor == 2 and npMinor < 37 then return false end
|
||||
|
||||
-- Verify the new tables exist
|
||||
if not pfUI.libdebuff_casts then return false end
|
||||
@@ -1182,6 +1193,58 @@ function lib:CleanupStaleTrackingData()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Clean ownBuffCasts (player-cast buffs on targets)
|
||||
if lib.ownBuffCasts then
|
||||
for guid, buffs in pairs(lib.ownBuffCasts) do
|
||||
for buffName, data in pairs(buffs) do
|
||||
local elapsed = now - (data.startTime or 0)
|
||||
local dur = data.duration or 0
|
||||
-- Remove if expired (duration > 0 and past end time) or stale (no duration and old)
|
||||
if (dur > 0 and elapsed > dur) or (dur <= 0 and elapsed > staleTime) then
|
||||
buffs[buffName] = nil
|
||||
end
|
||||
end
|
||||
if not next(buffs) then
|
||||
lib.ownBuffCasts[guid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Clean allBuffAuras (all-caster buff tracking)
|
||||
if lib.allBuffAuras then
|
||||
for guid, buffs in pairs(lib.allBuffAuras) do
|
||||
for buffName, casters in pairs(buffs) do
|
||||
for cGuid, data in pairs(casters) do
|
||||
local elapsed = now - (data.startTime or 0)
|
||||
local dur = data.duration or 0
|
||||
if (dur > 0 and elapsed > dur) or (dur <= 0 and elapsed > staleTime) then
|
||||
casters[cGuid] = nil
|
||||
end
|
||||
end
|
||||
if not next(casters) then
|
||||
buffs[buffName] = nil
|
||||
end
|
||||
end
|
||||
if not next(buffs) then
|
||||
lib.allBuffAuras[guid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Clean pendingBuffCasts (short-lived correlation data, 2 second TTL)
|
||||
if lib.pendingBuffCasts then
|
||||
for guid, spells in pairs(lib.pendingBuffCasts) do
|
||||
for spellId, data in pairs(spells) do
|
||||
if (now - (data.time or 0)) > 2 then
|
||||
spells[spellId] = nil
|
||||
end
|
||||
end
|
||||
if not next(spells) then
|
||||
lib.pendingBuffCasts[guid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Get the caster GUID for a debuff on a target
|
||||
@@ -3689,6 +3752,13 @@ if CleveRoids.hasNampower then
|
||||
ev:RegisterEvent("DEBUFF_REMOVED_OTHER")
|
||||
ev:RegisterEvent("UNIT_DIED") -- Instant cleanup on target death
|
||||
|
||||
-- BUFF_ADDED/REMOVED events require v2.30+ for auraSlot and state args
|
||||
if npMajor > 2 or (npMajor == 2 and npMinor >= 30) then
|
||||
ev:RegisterEvent("BUFF_ADDED_OTHER")
|
||||
ev:RegisterEvent("BUFF_REMOVED_SELF")
|
||||
ev:RegisterEvent("BUFF_REMOVED_OTHER")
|
||||
end
|
||||
|
||||
if CleveRoids.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00[Nampower]|r Registered UNIT_DIED for instant cleanup (v2.26+)")
|
||||
end
|
||||
@@ -4886,6 +4956,125 @@ ev:SetScript("OnEvent", function()
|
||||
end
|
||||
end
|
||||
|
||||
-- NAMPOWER v2.30+ BUFF_ADDED_OTHER - Confirm pending AURA_CAST_ON_OTHER data as buff
|
||||
elseif event == "BUFF_ADDED_OTHER" then
|
||||
if lib.hasPfUIEnhanced then return end
|
||||
|
||||
local guid = CleveRoids.NormalizeGUID(arg1)
|
||||
local spellId = arg3
|
||||
local state = arg7 -- 0=added, 1=removed, 2=modified
|
||||
|
||||
if not guid or not spellId then return end
|
||||
|
||||
-- Consume pending AURA_CAST data for this buff
|
||||
local pending = lib.pendingBuffCasts[guid] and lib.pendingBuffCasts[guid][spellId]
|
||||
if pending then
|
||||
local spellName = pending.spellName or (SpellInfo and SpellInfo(spellId))
|
||||
if spellName then
|
||||
local casterGuid = pending.casterGuid
|
||||
local duration = pending.duration
|
||||
local now = GetTime()
|
||||
|
||||
-- allBuffAuras: confirmed buff from any caster
|
||||
lib.allBuffAuras[guid] = lib.allBuffAuras[guid] or {}
|
||||
lib.allBuffAuras[guid][spellName] = lib.allBuffAuras[guid][spellName] or {}
|
||||
lib.allBuffAuras[guid][spellName][casterGuid or "unknown"] = {
|
||||
startTime = now,
|
||||
duration = duration or 0,
|
||||
rank = 0,
|
||||
}
|
||||
|
||||
-- ownBuffCasts: only if player is the caster
|
||||
local _, playerGuidRaw = UnitExists("player")
|
||||
local playerGuid = playerGuidRaw and CleveRoids.NormalizeGUID(playerGuidRaw)
|
||||
if playerGuid and casterGuid == playerGuid then
|
||||
lib.ownBuffCasts[guid] = lib.ownBuffCasts[guid] or {}
|
||||
lib.ownBuffCasts[guid][spellName] = {
|
||||
startTime = now,
|
||||
duration = duration or 0,
|
||||
spellId = spellId,
|
||||
casterGuid = casterGuid,
|
||||
}
|
||||
end
|
||||
end
|
||||
lib.pendingBuffCasts[guid][spellId] = nil
|
||||
end
|
||||
|
||||
-- NAMPOWER v2.30+ BUFF_REMOVED_SELF - Player's own buffs removed
|
||||
elseif event == "BUFF_REMOVED_SELF" then
|
||||
if lib.hasPfUIEnhanced then return end
|
||||
|
||||
local spellId = arg3
|
||||
local state = arg7
|
||||
if not spellId then return end
|
||||
if state == 2 then return end -- Stack decrease only, not full removal
|
||||
|
||||
local spellName = SpellInfo and SpellInfo(spellId)
|
||||
local _, playerGuidRaw = UnitExists("player")
|
||||
local playerGuid = playerGuidRaw and CleveRoids.NormalizeGUID(playerGuidRaw)
|
||||
|
||||
if spellName and playerGuid then
|
||||
if lib.ownBuffCasts[playerGuid] then
|
||||
lib.ownBuffCasts[playerGuid][spellName] = nil
|
||||
if not next(lib.ownBuffCasts[playerGuid]) then
|
||||
lib.ownBuffCasts[playerGuid] = nil
|
||||
end
|
||||
end
|
||||
if lib.allBuffAuras[playerGuid] then
|
||||
lib.allBuffAuras[playerGuid][spellName] = nil
|
||||
if not next(lib.allBuffAuras[playerGuid]) then
|
||||
lib.allBuffAuras[playerGuid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Also prune from OverflowBuffs (existing system)
|
||||
if spellId and CleveRoids.OverflowBuffs and CleveRoids.OverflowBuffs[spellId] then
|
||||
CleveRoids.OverflowBuffs[spellId] = nil
|
||||
end
|
||||
|
||||
-- NAMPOWER v2.30+ BUFF_REMOVED_OTHER - Buffs removed from other units
|
||||
elseif event == "BUFF_REMOVED_OTHER" then
|
||||
if lib.hasPfUIEnhanced then return end
|
||||
|
||||
local guid = CleveRoids.NormalizeGUID(arg1)
|
||||
local spellId = arg3
|
||||
local state = arg7
|
||||
if not guid or not spellId then return end
|
||||
if state == 2 then return end -- Stack decrease only, not full removal
|
||||
|
||||
local spellName = SpellInfo and SpellInfo(spellId)
|
||||
if spellName then
|
||||
if lib.allBuffAuras[guid] then
|
||||
lib.allBuffAuras[guid][spellName] = nil
|
||||
if not next(lib.allBuffAuras[guid]) then
|
||||
lib.allBuffAuras[guid] = nil
|
||||
end
|
||||
end
|
||||
if lib.ownBuffCasts[guid] then
|
||||
lib.ownBuffCasts[guid][spellName] = nil
|
||||
if not next(lib.ownBuffCasts[guid]) then
|
||||
lib.ownBuffCasts[guid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Clean pending correlation data
|
||||
if lib.pendingBuffCasts[guid] then
|
||||
lib.pendingBuffCasts[guid][spellId] = nil
|
||||
if not next(lib.pendingBuffCasts[guid]) then
|
||||
lib.pendingBuffCasts[guid] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Also clean AllCasterAuraTracking (existing system)
|
||||
if CleveRoids.AllCasterAuraTracking[guid] then
|
||||
CleveRoids.AllCasterAuraTracking[guid][spellId] = nil
|
||||
if not next(CleveRoids.AllCasterAuraTracking[guid]) then
|
||||
CleveRoids.AllCasterAuraTracking[guid] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- NAMPOWER v2.26+ UNIT_DIED - Instant cleanup on target death
|
||||
elseif event == "UNIT_DIED" then
|
||||
local guid = arg1
|
||||
@@ -4918,6 +5107,17 @@ ev:SetScript("OnEvent", function()
|
||||
lib.recentMisses[guid] = nil
|
||||
end
|
||||
|
||||
-- Clean up buff tracking tables
|
||||
if lib.ownBuffCasts[guid] then
|
||||
lib.ownBuffCasts[guid] = nil
|
||||
end
|
||||
if lib.allBuffAuras[guid] then
|
||||
lib.allBuffAuras[guid] = nil
|
||||
end
|
||||
if lib.pendingBuffCasts[guid] then
|
||||
lib.pendingBuffCasts[guid] = nil
|
||||
end
|
||||
|
||||
-- Clean up cast tracking for this unit (they can't be casting if dead)
|
||||
if not lib.hasPfUI76 and CleveRoids.castTracking[guid] then
|
||||
CleveRoids.castTracking[guid] = nil
|
||||
|
||||
Reference in New Issue
Block a user