fixes for immunity system and errors

This commit is contained in:
Jrc13245
2026-01-11 21:25:50 -05:00
parent a02fa29cbd
commit 5af6296550
+106 -61
View File
@@ -2235,7 +2235,9 @@ local _string_format = string.format
local _string_sub = string.sub
local _tostring = tostring
local _next = next
local _pairs = pairs
local _getn = table.getn -- Lua 5.0 compatible table length
local _table_insert = table.insert -- Lua 5.0 compatible
-- PERFORMANCE: Static buffers for removal tracking - reused every frame
-- Using mark-and-sweep pattern instead of table.remove() for O(1) removal
@@ -2259,10 +2261,12 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
_lastDelayedTrackingUpdate = currentTime
-- PERFORMANCE: Early exit if all queues are empty
local hasJudgements = lib.pendingJudgements and lib.pendingJudgements[1]
local hasPersonal = lib.pendingPersonalDebuffs and lib.pendingPersonalDebuffs[1]
local hasCC = lib.pendingCCDebuffs and lib.pendingCCDebuffs[1]
local hasShared = lib.pendingSharedDebuffs and lib.pendingSharedDebuffs[1]
-- NOTE: Use next() instead of [1] to handle array holes from table.remove()
-- Array holes can occur when combat log handlers remove entries mid-iteration
local hasJudgements = lib.pendingJudgements and _next(lib.pendingJudgements)
local hasPersonal = lib.pendingPersonalDebuffs and _next(lib.pendingPersonalDebuffs)
local hasCC = lib.pendingCCDebuffs and _next(lib.pendingCCDebuffs)
local hasShared = lib.pendingSharedDebuffs and _next(lib.pendingSharedDebuffs)
local hasOverrides = lib.rankRefreshOverrides and _next(lib.rankRefreshOverrides)
-- DEBUG: Track pending queue state - check EVERY time to diagnose issue
@@ -2281,6 +2285,22 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
)
end
end
-- Log personal debuff queue state when items exist but hasPersonal might be false
if personalCount > 0 then
if not lib._lastPersonalQueueLog or (currentTime - lib._lastPersonalQueueLog) > 0.5 then
lib._lastPersonalQueueLog = currentTime
local firstItem = lib.pendingPersonalDebuffs[1]
local firstItemInfo = "NIL"
if firstItem then
firstItemInfo = _string_format("spellID:%s,targetGUID:%s",
_tostring(firstItem.spellID or "nil"), firstItem.targetGUID and "exists" or "nil")
end
DEFAULT_CHAT_FRAME:AddMessage(
_string_format("|cffaaaaaa[Personal Queue]|r count:%d, hasPersonal:%s, [1]:%s",
personalCount, hasPersonal and "TRUE" or "FALSE", firstItemInfo)
)
end
end
end
if not (hasJudgements or hasPersonal or hasCC or hasShared or hasOverrides) then
@@ -2351,7 +2371,12 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
-- Process pending personal debuffs
if hasPersonal then
local pendingCount = _getn(lib.pendingPersonalDebuffs)
-- Count entries properly using pairs (handles array holes)
local pendingCount = 0
for _ in _pairs(lib.pendingPersonalDebuffs) do
pendingCount = pendingCount + 1
end
-- Debug: Show pending count every few seconds (avoid spam)
if debug and pendingCount > 0 then
if not lib._lastPendingDebugTime or (currentTime - lib._lastPendingDebugTime) > 2.0 then
@@ -2362,12 +2387,12 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
end
end
local writeIdx = 0
local pendingList = lib.pendingPersonalDebuffs
-- Use pairs() to iterate and rebuild without holes
-- This handles array holes created by table.remove() in combat log handlers
local newPendingList = {}
for i = 1, _getn(pendingList) do
local pending = pendingList[i]
-- Guard against nil entries (can occur if combat log events remove items during iteration)
for _, pending in _pairs(lib.pendingPersonalDebuffs) do
-- Process each entry (pairs handles holes correctly)
if pending then
local elapsed = currentTime - pending.timestamp
@@ -2378,6 +2403,16 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
local isBleedSpell = CleveRoids.BleedSpellIDs and CleveRoids.BleedSpellIDs[pending.spellID]
local bleedVerified = true
-- DEBUG: Log verification attempt for bleed spells
if debug and isBleedSpell then
local spellNameDbg = _SpellInfo(pending.spellID) or "Unknown"
DEFAULT_CHAT_FRAME:AddMessage(
_string_format("|cff00aaff[Bleed Verify Start]|r %s (ID:%d) on %s - hasSuperwow:%s, targetGUID:%s",
spellNameDbg, pending.spellID, pending.targetName or "Unknown",
hasSuperwow and "yes" or "NO", pending.targetGUID and "exists" or "NIL")
)
end
if isBleedSpell and hasSuperwow and pending.targetGUID then
-- Check if mob is in bleed whitelist (skip verification for known bleeders)
local isWhitelisted = CleveRoids.MobsThatBleed and CleveRoids.MobsThatBleed[pending.targetGUID]
@@ -2397,22 +2432,44 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
)
end
else
-- Target died WITHOUT "afflicted by" message - bleed never landed = immunity
bleedVerified = false
if pending.targetName and pending.targetName ~= "" then
local spellNameForImmunity = _SpellInfo(pending.spellID) or "Bleed"
if not CleveRoids_ImmunityData["bleed"] then
CleveRoids_ImmunityData["bleed"] = {}
end
CleveRoids_ImmunityData["bleed"][pending.targetName] = true
-- Target died WITHOUT "afflicted by" message
-- BUT: Don't record immunity for one-shot kills!
-- If target died within 0.5s of cast, the bleed didn't have time to apply
-- even on a valid target. We can't determine immunity from instant kills.
local timeSinceCast = currentTime - pending.timestamp
local ONE_SHOT_THRESHOLD = 0.5 -- seconds
if timeSinceCast < ONE_SHOT_THRESHOLD then
-- One-shot kill - can't determine immunity, skip recording
-- Set bleedVerified = false so we don't add to tracking or remove existing immunity
bleedVerified = false
if debug then
local spellNameDebug = _SpellInfo(pending.spellID) or "Bleed"
DEFAULT_CHAT_FRAME:AddMessage(
_string_format("|cffff6600[Bleed Immunity]|r %s is immune to bleed (%s) - target died without 'afflicted by' message",
pending.targetName, spellNameForImmunity)
_string_format("|cffaaaaaa[Bleed Skip]|r %s on %s - target died too quickly (%.2fs), can't determine immunity",
spellNameDebug, pending.targetName or "Unknown", timeSinceCast)
)
end
-- Note: We set bleedVerified = false but DON'T record immunity
-- This is intentional - one-shots are inconclusive
else
-- Target lived long enough but no "afflicted by" = immunity
bleedVerified = false
if pending.targetName and pending.targetName ~= "" then
local spellNameForImmunity = _SpellInfo(pending.spellID) or "Bleed"
if not CleveRoids_ImmunityData["bleed"] then
CleveRoids_ImmunityData["bleed"] = {}
end
CleveRoids_ImmunityData["bleed"][pending.targetName] = true
if debug then
DEFAULT_CHAT_FRAME:AddMessage(
_string_format("|cffff6600[Bleed Immunity]|r %s is immune to bleed (%s) - target died without 'afflicted by' message (%.2fs)",
pending.targetName, spellNameForImmunity, timeSinceCast)
)
end
end
end
end
else
@@ -2529,31 +2586,25 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
end
end
end
-- Item processed, don't copy to output
-- Item processed, don't add to new list
else
-- Item not ready, keep it
writeIdx = writeIdx + 1
if writeIdx ~= i then
pendingList[writeIdx] = pending
end
-- Item not ready, keep it in the new list
_table_insert(newPendingList, pending)
end
end -- if pending
end
-- PERFORMANCE: Clear remaining slots
for i = writeIdx + 1, _getn(pendingList) do
pendingList[i] = nil
end
-- Replace old list with compacted new list (no holes)
lib.pendingPersonalDebuffs = newPendingList
end
-- Process pending CC debuffs for immunity detection
if hasCC then
local writeIdx = 0
local pendingList = lib.pendingCCDebuffs
-- Use pairs() to iterate and rebuild without holes (same fix as personal debuffs)
local newPendingList = {}
for i = 1, _getn(pendingList) do
local pending = pendingList[i]
-- Guard against nil entries (can occur if combat log events remove items during iteration)
for _, pending in _pairs(lib.pendingCCDebuffs) do
-- Process each entry (pairs handles holes correctly)
if pending then
local elapsed = currentTime - pending.timestamp
@@ -2711,28 +2762,28 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
)
end
end
-- Item processed, don't copy to output
-- Item processed, don't add to new list
else
-- Item not ready, keep it
writeIdx = writeIdx + 1
if writeIdx ~= i then
pendingList[writeIdx] = pending
end
-- Item not ready, keep it in the new list
_table_insert(newPendingList, pending)
end
end -- if pending
end
-- PERFORMANCE: Clear remaining slots
for i = writeIdx + 1, _getn(pendingList) do
pendingList[i] = nil
end
-- Replace old list with compacted new list (no holes)
lib.pendingCCDebuffs = newPendingList
end
-- Process pending shared debuffs for immunity detection
if hasShared then
local writeIdx = 0
local pendingList = lib.pendingSharedDebuffs
local pendingCount = _getn(pendingList)
-- Use pairs() to iterate and rebuild without holes (same fix as personal/CC debuffs)
local newPendingList = {}
-- Count for debug output
local pendingCount = 0
for _ in _pairs(lib.pendingSharedDebuffs) do
pendingCount = pendingCount + 1
end
if debug then
DEFAULT_CHAT_FRAME:AddMessage(
@@ -2740,8 +2791,7 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
)
end
for i = 1, pendingCount do
local pending = pendingList[i]
for _, pending in _pairs(lib.pendingSharedDebuffs) do
-- Guard against nil entries (can occur if combat log events remove items during iteration)
if pending then
local elapsed = currentTime - pending.timestamp
@@ -2838,21 +2888,16 @@ delayedTrackingFrame:SetScript("OnUpdate", function()
end
end
end
-- Item processed, don't copy to output
-- Item processed, don't add to new list
else
-- Item not ready, keep it
writeIdx = writeIdx + 1
if writeIdx ~= i then
pendingList[writeIdx] = pending
end
-- Item not ready, keep it in the new list
_table_insert(newPendingList, pending)
end
end -- if pending
end
-- PERFORMANCE: Clear remaining slots
for i = writeIdx + 1, _getn(pendingList) do
pendingList[i] = nil
end
-- Replace old list with compacted new list (no holes)
lib.pendingSharedDebuffs = newPendingList
end
-- Clean up old rank refresh overrides (older than 2 seconds)