mirror of
https://github.com/brues-code/SuperCleveRoidMacros.git
synced 2026-09-16 03:38:00 +00:00
fixes for immunity system and errors
This commit is contained in:
+106
-61
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user