--[[-------------------------------------------------------------------- |
LibResInfo-1.0 |
Library to provide information about resurrections in your group. |
Copyright (c) 2012-2013 A. Kinley <addons@phanx.net>. All rights reserved. |
See the accompanying README and LICENSE files for more information. |
http://www.wowinterface.com/downloads/info21467-LibResInfo-1.0.html |
http://wow.curseforge.com/addons/libresinfo/ |
------------------------------------------------------------------------ |
TODO: |
* Handle Reincarnation |
----------------------------------------------------------------------]] |
|
local DEBUG_LEVEL = GetAddOnMetadata("LibResInfo-1.0", "Version") and 1 or 0 |
local DEBUG_FRAME = ChatFrame3 |
|
------------------------------------------------------------------------ |
|
local MAJOR, MINOR = "LibResInfo-1.0", 18 |
assert(LibStub, MAJOR.." requires LibStub") |
assert(LibStub("CallbackHandler-1.0"), MAJOR.." requires CallbackHandler-1.0") |
local lib, oldminor = LibStub:NewLibrary(MAJOR, MINOR) |
if not lib then return end |
|
------------------------------------------------------------------------ |
|
local callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib) |
local eventFrame = lib.eventFrame or CreateFrame("Frame") |
|
local guidFromUnit = lib.guidFromUnit or {} -- t[unit] = guid -- table lookup is faster than calling UnitGUID |
local nameFromGUID = lib.nameFromGUID or {} -- t[guid] = name |
local unitFromGUID = lib.unitFromGUID or {} -- t[guid] = unit |
|
local castingSingle = lib.castingSingle or {} -- t[casterGUID] = { startTime = <number>, endTime = <number>, target = <guid> } |
local castingMass = lib.castingMass or {} -- t[casterGUID] = endTime |
local hasPending = lib.hasPending or {} -- t[targetGUID] = endTime |
|
local hasSoulstone = lib.hasSoulstone or {} -- t[targetGUID] = <boolean> |
local isDead = lib.isDead or {} -- t[targetGUID] = <boolean> |
local isGhost = lib.isGhost or {} -- t[targetGUID] = <boolean> |
|
------------------------------------------------------------------------ |
|
lib.callbacks = callbacks |
lib.eventFrame = eventFrame |
|
lib.guidFromUnit = guidFromUnit |
lib.nameFromGUID = nameFromGUID |
lib.unitFromGUID = unitFromGUID |
|
lib.castingSingle = castingSingle |
lib.castingMass = castingMass |
lib.hasPending = hasPending |
|
lib.hasSoulstone = hasSoulstone |
lib.isDead = isDead |
lib.isGhost = isGhost |
|
------------------------------------------------------------------------ |
|
local RESURRECT_PENDING_TIME = 60 |
local RELEASE_PENDING_TIME = 360 |
local RECENTLY_MASS_RESURRECTED = GetSpellInfo(95223) |
local SOULSTONE = GetSpellInfo(20707) |
|
local resSpells = { |
[2008] = GetSpellInfo(2008), -- Ancestral Spirit (shaman) |
[8342] = GetSpellInfo(8342), -- Defibrillate (item: Goblin Jumper Cables) |
[22999] = GetSpellInfo(22999), -- Defibrillate (item: Goblin Jumper Cables XL) |
[54732] = GetSpellInfo(54732), -- Defibrillate (item: Gnomish Army Knife) |
[126393] = GetSpellInfo(126393), -- Eternal Guardian (hunter pet: quilien) |
[61999] = GetSpellInfo(61999), -- Raise Ally (death knight) |
[20484] = GetSpellInfo(20484), -- Rebirth (druid) |
[113269] = GetSpellInfo(113269), -- Rebirth (prot/holy paladin symbiosis) |
[7328] = GetSpellInfo(7328), -- Redemption (paladin) |
[2006] = GetSpellInfo(2006), -- Resurrection (priest) |
[115178] = GetSpellInfo(115178), -- Resuscitate (monk) |
[50769] = GetSpellInfo(50769), -- Revive (druid) |
[982] = GetSpellInfo(982), -- Revive Pet (hunter) |
[20707] = GetSpellInfo(20707), -- Soulstone (warlock) |
[83968] = GetSpellInfo(83968), -- Mass Resurrection |
} |
|
------------------------------------------------------------------------ |
|
local next, pairs, GetNumGroupMembers, GetTime, IsInGroup, IsInRaid, UnitAura, UnitCastingInfo, UnitGUID, UnitHasIncomingResurrection, UnitHealth, UnitIsConnected, UnitIsDead, UnitIsDeadOrGhost, UnitIsGhost, UnitName |
= next, pairs, GetNumGroupMembers, GetTime, IsInGroup, IsInRaid, UnitAura, UnitCastingInfo, UnitGUID, UnitHasIncomingResurrection, UnitHealth, UnitIsConnected, UnitIsDead, UnitIsDeadOrGhost, UnitIsGhost, UnitName |
|
------------------------------------------------------------------------ |
|
local function debug(level, text, ...) |
if level <= DEBUG_LEVEL then |
if ... then |
if type(text) == "string" and strfind(text, "%%[dfqsx%d%.]") then |
text = format(text, ...) |
else |
text = strjoin(" ", tostringall(text, ...)) |
end |
else |
text = tostring(text) |
end |
DEBUG_FRAME:AddMessage("|cff00ddba[LRI]|r " .. text) |
end |
end |
|
local newTable, remTable |
do |
local pool = {} |
function newTable() |
local t = next(pool) |
if t then |
pool[t] = nil |
return t |
end |
return {} |
end |
function remTable(t) |
pool[wipe(t)] = true |
return nil |
end |
end |
|
------------------------------------------------------------------------ |
|
lib.callbacksInUse = lib.callbacksInUse or {} |
|
eventFrame:SetScript("OnEvent", function(self, event, ...) |
return self[event] and self[event](self, event, ...) |
end) |
|
function callbacks:OnUsed(lib, callback) |
if not next(lib.callbacksInUse) then |
debug(1, "Callbacks in use! Starting up...") |
eventFrame:RegisterEvent("GROUP_ROSTER_UPDATE") |
eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD") |
eventFrame:RegisterEvent("INCOMING_RESURRECT_CHANGED") |
eventFrame:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED") |
eventFrame:RegisterEvent("UNIT_SPELLCAST_START") |
eventFrame:RegisterEvent("UNIT_SPELLCAST_STOP") |
eventFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED") |
eventFrame:RegisterEvent("UNIT_AURA") |
eventFrame:RegisterEvent("UNIT_CONNECTION") |
eventFrame:RegisterEvent("UNIT_HEALTH") |
eventFrame:GROUP_ROSTER_UPDATE("OnUsed") |
end |
lib.callbacksInUse[callback] = true |
end |
|
function callbacks:OnUnused(lib, callback) |
lib.callbacksInUse[callback] = nil |
if not next(lib.callbacksInUse) then |
debug(1, "No callbacks in use. Shutting down...") |
eventFrame:UnregisterAllEvents() |
eventFrame:Hide() |
wipe(guidFromUnit) |
wipe(nameFromGUID) |
wipe(unitFromGUID) |
wipe(castingMass) |
wipe(hasPending) |
wipe(hasSoulstone) |
wipe(isDead) |
wipe(isGhost) |
for caster, data in pairs(castingSingle) do |
castingSingle[caster] = remTable(data) |
end |
end |
end |
|
------------------------------------------------------------------------ |
|
function lib.RegisterAllCallbacks(handler, method, includeMassRes) |
lib.RegisterCallback(handler, "LibResInfo_ResCastStarted", method) |
lib.RegisterCallback(handler, "LibResInfo_ResCastCancelled", method) |
lib.RegisterCallback(handler, "LibResInfo_ResCastFinished", method) |
|
if includeMassRes then |
lib.RegisterCallback(handler, "LibResInfo_MassResStarted", method) |
lib.RegisterCallback(handler, "LibResInfo_MassResCancelled", method) |
lib.RegisterCallback(handler, "LibResInfo_MassResFinished", method) |
end |
|
lib.RegisterCallback(handler, "LibResInfo_ResPending", method) |
lib.RegisterCallback(handler, "LibResInfo_ResUsed", method) |
lib.RegisterCallback(handler, "LibResInfo_ResExpired", method) |
end |
|
------------------------------------------------------------------------ |
-- Returns information about the res being cast on the specified unit. |
-- Arguments: unit (unitID or GUID) |
-- Returns: resType (string), endTime (number), caster (unitID), casterGUID |
-- * All returns are nil if no res is being cast on the unit. |
-- * resType is one of: |
-- - SELFRES if the unit has a Soulstone or other self-res ability available, |
-- - PENDING if the unit already has a res available to accept, or |
-- - CASTING if a res is being cast on the unit. |
-- * caster and casterGUID are nil if the unit is being Mass Ressed. |
------------------------------------------------------------------------ |
|
function lib:UnitHasIncomingRes(unit) |
if type(unit) ~= "string" then return end |
local guid |
if strmatch(unit, "^0x") then |
guid = unit |
unit = unitFromGUID[guid] |
else |
guid = UnitGUID(unit) |
unit = unitFromGUID[guid] |
end |
if not guid or not unit or not UnitIsDeadOrGhost(unit) or not UnitIsConnected(unit) then |
return |
end |
if hasPending[guid] then |
local state = hasSoulstone[guid] and "SELFRES" or "PENDING" |
--debug(2, "UnitHasIncomingRes", nameFromGUID[guid], state) |
return state, hasPending[guid] |
end |
|
local state, firstCaster, firstEnd |
for caster, data in pairs(castingSingle) do |
if data.target == guid then |
if not firstEnd or data.endTime < firstEnd then |
state, firstCaster, firstEnd = "CASTING", caster, data.endTime |
end |
end |
end |
if not UnitDebuff(unit, RECENTLY_MASS_RESURRECTED) then |
for caster, endTime in pairs(castingMass) do |
if not firstEnd or endTime < firstEnd then |
state, firstCaster, firstEnd = "MASSRES", caster, endTime |
end |
end |
end |
if state and firstCaster and firstEnd then |
--debug(2, "UnitHasIncomingRes", nameFromGUID[guid], state, nameFromGUID[firstCaster]) |
return state, firstEnd, unitFromGUID[firstCaster], firstCaster |
end |
--debug(3, "UnitHasIncomingRes", nameFromGUID[guid], "nil") |
end |
|
------------------------------------------------------------------------ |
-- Return information about the res being cast by the specified unit. |
-- Arguments: unit (unitID or GUID) |
-- Returns: endTime (number), target (unitID), targetGUID (guid), isFirst (boolean) |
-- * all returns are nil if the unit is not casting a res |
-- * target and targetGUID are nil if the unit is casting Mass Res |
------------------------------------------------------------------------ |
|
function lib:UnitIsCastingRes(unit) |
if type(unit) ~= "string" then return end |
local guid |
if strmatch(unit, "^0x") then |
guid = unit |
unit = unitFromGUID[guid] |
else |
guid = UnitGUID(unit) |
unit = unitFromGUID[guid] |
end |
if not guid or not unit then |
return |
end |
|
local casting = castingSingle[guid] |
if casting then |
local endTime, target, isFirst = casting.endTime, casting.target, true |
-- TODO: Handle edge case where this function is called in between the cast start and the target identification? |
for caster, data in pairs(castingSingle) do |
if data.target == target and data.endTime < endTime then |
isFirst = false |
break |
end |
end |
--debug(2, "UnitIsCastingRes", nameFromGUID[guid], "casting on", nameFromGUID[casting.target], isFirst and "(first)" or "(duplicate)") |
return endTime, unitFromGUID[casting.target], casting.target, isFirst |
end |
|
casting = castingMass[guid] |
if casting then |
local endTime, isFirst = casting, true |
for caster, endTime2 in pairs(castingMass) do |
if endTime2 < endTime then |
isFirst = false |
break |
end |
end |
--debug(2, "UnitIsCastingRes", nameFromGUID[guid], "casting Mass Res", isFirst and "(first)" or "(duplicate)") |
return endTime, nil, nil, isFirst |
end |
|
--debug(3, "UnitIsCastingRes", nameFromGUID[guid], "nil") |
end |
|
------------------------------------------------------------------------ |
-- Handle group changes: |
|
local function AddUnit(unit) |
local guid = UnitGUID(unit) |
if not guid then return end |
guidFromUnit[unit] = guid |
nameFromGUID[guid] = UnitName(unit) |
unitFromGUID[guid] = unit |
-- Check for soulstones: |
eventFrame:UNIT_AURA("AddUnit", unit) |
end |
|
function eventFrame:GROUP_ROSTER_UPDATE(event) |
debug(3, event) |
|
-- Update guid <==> unit mappings: |
wipe(guidFromUnit) |
wipe(unitFromGUID) |
if IsInRaid() then |
for i = 1, GetNumGroupMembers() do |
AddUnit("raid"..i) |
AddUnit("raidpet"..i) |
end |
else |
AddUnit("player") |
AddUnit("pet") |
if IsInGroup() then |
for i = 1, GetNumGroupMembers() - 1 do |
AddUnit("party"..i) |
AddUnit("partypet"..i) |
end |
end |
end |
|
-- Remove data for single casters no longer in the group: |
for caster, data in pairs(castingSingle) do |
if not unitFromGUID[caster] then |
local target = data.target |
castingSingle[caster] = remTable(data) |
debug(1, ">> ResCastCancelled on", nameFromGUID[target], "by", nameFromGUID[caster], "(caster left group)") |
callbacks:Fire("LibResInfo_ResCastCancelled", unitFromGUID[target], target, nil, caster) |
end |
end |
|
-- Remove data for mass casters no longer in the group: |
for caster in pairs(castingMass) do |
if not unitFromGUID[caster] then |
castingMass[caster] = nil |
debug(1, ">> MassResCancelled by", nameFromGUID[caster], "(left group)") |
callbacks:Fire("LibResInfo_MassResCancelled", nil, caster) |
end |
end |
|
-- Remove data for targets no longer in the group: |
for caster, data in pairs(castingSingle) do |
local target = data.target |
if not unitFromGUID[target] then |
castingSingle[caster] = remTable(data) |
-- TODO: Is this callback needed, or will the cast cancel on its own? |
debug(1, ">> ResCastCancelled on", nameFromGUID[target], "by", nameFromGUID[caster], "(target left group)") |
callbacks:Fire("LibResInfo_ResCastCancelled", nil, target, unitFromGUID[caster], caster) |
end |
end |
|
-- Remove data for waiters no longer in the group: |
for target in pairs(hasPending) do |
if not unitFromGUID[target] then |
hasPending[target] = nil |
debug(1, ">> ResExpired on", nameFromGUID[target], "(left group)") |
callbacks:Fire("LibResInfo_ResExpired", nil, target) |
end |
end |
|
-- Unregister unit events and stop the timer if there are no waiters: |
if not next(hasPending) then |
debug(3, "Nobody pending, stop timer") |
self:Hide() |
end |
|
-- Unregister CLEU if there are no casts: |
if not next(castingSingle) and not next(castingMass) then |
debug(3, "Nobody casting, unregistering CLEU") |
self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") |
end |
|
-- Remove names no longer in the group: |
for guid, name in pairs(nameFromGUID) do |
if not unitFromGUID[guid] then |
debug(4, name, "is no longer in the group") |
nameFromGUID[guid] = nil |
end |
end |
end |
|
eventFrame.PLAYER_ENTERING_WORLD = eventFrame.GROUP_ROSTER_UPDATE |
|
------------------------------------------------------------------------ |
|
function eventFrame:INCOMING_RESURRECT_CHANGED(event, unit) |
local guid = guidFromUnit[unit] |
if not guid then return end |
|
local hasRes = UnitHasIncomingResurrection(unit) |
debug(3, event, nameFromGUID[guid], hasRes) |
|
if hasRes then |
-- Unit has a res incoming. Match it to a spell. |
local now = GetTime() |
for caster, data in pairs(castingSingle) do |
if not data.target and data.startTime - now < 10 then |
-- Found it! |
data.target = guid |
debug(1, ">> ResCastStarted on", nameFromGUID[guid], "by", nameFromGUID[caster], "in", event) |
callbacks:Fire("LibResInfo_ResCastStarted", unit, guid, unitFromGUID[caster], caster, data.endTime) |
break |
end |
end |
-- TODO: Why was I searching for finished casts here??? |
else |
-- Check if unit previously had any resses. |
for caster, data in pairs(castingSingle) do |
if data.target == guid then |
debug(4, nameFromGUID[caster], "was casting...") |
if data.startTime then |
debug(4, "...and stopped.") |
castingSingle[caster] = remTable(data) |
debug(1, ">> ResCastCancelled", "on", nameFromGUID[guid], "by", nameFromGUID[casterGUID], "in", event) |
callbacks:Fire("LibResInfo_ResCastCancelled", unit, guid, unitFromGUID[casterGUID], casterGUID) |
else |
debug(4, "...and finished.") |
castingSingle[caster] = remTable(data) |
hasPending[guid] = nil |
debug(1, ">> ResCastFinished", "on", nameFromGUID[guid], "by", nameFromGUID[casterGUID], "in", event) |
callbacks:Fire("LibResInfo_ResCastFinished", unit, guid, unitFromGUID[casterGUID], casterGUID) |
self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") |
end |
end |
end |
end |
end |
|
------------------------------------------------------------------------ |
|
function eventFrame:UNIT_SPELLCAST_START(event, unit, spellName, _, _, spellID) |
if not resSpells[spellID] then return end |
local guid = guidFromUnit[unit] |
if not guid then return end |
debug(3, event, nameFromGUID[guid], "casting", spellName) |
|
local _, _, _, _, startTime, endTime = UnitCastingInfo(unit) |
|
if spellID == 83968 then -- Mass Resurrection |
castingMass[guid] = endTime / 1000 |
debug(1, ">> MassResStarted", nameFromGUID[guid]) |
callbacks:Fire("LibResInfo_MassResStarted", unit, guid, endTime / 1000) |
return |
end |
|
local data = newTable() |
data.startTime = startTime / 1000 |
data.endTime = endTime / 1000 |
castingSingle[guid] = data |
end |
|
function eventFrame:UNIT_SPELLCAST_SUCCEEDED(event, unit, spellName, _, _, spellID) |
if not resSpells[spellID] then return end |
local guid = guidFromUnit[unit] |
if not guid then return end |
|
debug(3, event, nameFromGUID[guid], "finished", spellName) |
|
if spellID == 83968 then -- Mass Resurrection |
castingMass[guid] = nil |
debug(1, ">> MassResFinished", nameFromGUID[guid]) |
callbacks:Fire("LibResInfo_MassResFinished", unit, guid) |
self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") |
return |
end |
|
local data = castingSingle[guid] |
if data then -- No START event for instant cast spells. |
local target = data.target |
if not target then |
-- Probably Soulstone precast on a live target. |
return |
end |
data.finished = true -- Flag so STOP can ignore this. |
debug(1, ">> ResCastFinished", "on", nameFromGUID[target], "by", nameFromGUID[guid], "in", event) |
callbacks:Fire("LibResInfo_ResCastFinished", unitFromGUID[target], target, unit, guid) |
end |
|
debug(3, "Registering CLEU") |
self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") |
end |
|
function eventFrame:UNIT_SPELLCAST_STOP(event, unit, spellName, _, _, spellID) |
if not resSpells[spellID] then return end |
local guid = guidFromUnit[unit] |
if not guid then return end |
|
debug(3, event, nameFromGUID[guid], "stopped", spellName) |
|
if spellID == 83968 then -- Mass Resurrection |
if not castingMass[guid] then return end -- already SUCCEEDED |
castingMass[guid] = nil |
debug(1, ">> MassResCancelled", nameFromGUID[guid]) |
callbacks:Fire("LibResInfo_MassResCancelled", unit, guid) |
else |
local data = castingSingle[guid] |
if data then |
local target = data.target |
local finished = data.finished |
castingSingle[guid] = remTable(data) |
if finished or not target then |
-- no target = Probably Soulstone precast on a live target. |
-- finished = Cast finished. Don't fire a callback or unregister CLEU. |
return |
end |
debug(1, ">> ResCastCancelled", "on", nameFromGUID[target], "by", nameFromGUID[guid]) |
callbacks:Fire("LibResInfo_ResCastCancelled", unitFromGUID[target], target, unit, guid) |
end |
end |
|
-- Unregister CLEU if there are no casts: |
if not next(castingSingle) and not next(castingMass) then |
debug(3, "Nobody casting, unregistering CLEU") |
self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") |
end |
end |
|
eventFrame.UNIT_SPELLCAST_INTERRUPTED = eventFrame.UNIT_SPELLCAST_STOP |
|
------------------------------------------------------------------------ |
|
function eventFrame:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, combatEvent, hideCaster, sourceGUID, sourceName, sourceFlags, sourceRaidFlags, destGUID, destName, destFlags, destRaidFlags, spellID, spellName, spellSchool) |
if combatEvent ~= "SPELL_RESURRECT" then return end |
|
local destUnit = unitFromGUID[destGUID] |
if not destUnit then return end |
debug(3, combatEvent, "on", destName, "by", sourceName) |
|
local now = GetTime() |
local endTime = now + RESURRECT_PENDING_TIME |
|
hasPending[destGUID] = endTime |
|
self:Show() |
|
debug(1, ">> ResPending", "on", strmatch(destName, "[^%-]+"), "by", strmatch(sourceName, "[^%-]+")) |
callbacks:Fire("LibResInfo_ResPending", destUnit, destGUID, endTime) |
|
-- Unregister CLEU if there are no casts: |
if not next(castingSingle) and not next(castingMass) then |
-- TODO: Keep track of number of instant casts? |
-- Seems unlikely that multiple casts would end so close together that this would be an issue. |
debug(3, "Nobody casting, unregistering CLEU") |
self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") |
end |
end |
|
------------------------------------------------------------------------ |
|
function eventFrame:UNIT_AURA(event, unit) |
local guid = guidFromUnit[unit] |
if not guid then return end |
debug(5, event, unit) |
|
if not isDead[guid] then |
local stoned = UnitAura(unit, SOULSTONE) |
if stoned ~= hasSoulstone[guid] then |
if not stoned and UnitHealth(unit) <= 1 then |
return |
end |
hasSoulstone[guid] = stoned |
debug(2, nameFromGUID[guid], stoned and "gained" or "lost", SOULSTONE) |
end |
return |
end |
|
if UnitIsGhost(unit) and not isGhost[guid] then |
isGhost[guid] = true |
if hasPending[guid] then |
hasPending[guid] = nil |
debug(1, ">> ResExpired", nameFromGUID[guid], "(released)") |
callbacks:Fire("LibResInfo_ResExpired", unit, guid) |
end |
end |
end |
|
function eventFrame:UNIT_CONNECTION(event, unit) |
local guid = guidFromUnit[unit] |
if not guid then return end |
debug(4, event, unit) |
|
if hasPending[unit] and not UnitIsConnected(unit) then |
hasPending[guid] = nil |
debug(1, ">> ResExpired", nameFromGUID[guid], "(offline)") |
callbacks:Fire("LibResInfo_ResExpired", unit, guid) |
end |
end |
|
function eventFrame:UNIT_HEALTH(event, unit) |
local guid = guidFromUnit[unit] |
if not guid then return end |
debug(5, event, unit) |
|
local dead = UnitIsDead(unit) |
|
if dead and not isDead[guid] then |
debug(2, nameFromGUID[guid], "is now dead") |
isDead[guid] = true |
if hasSoulstone[guid] then |
local endTime = GetTime() + RELEASE_PENDING_TIME |
hasPending[guid] = endTime |
debug(1, ">> ResPending", nameFromGUID[guid], SOULSTONE) |
callbacks:Fire("LibResInfo_ResPending", unit, guid, endTime, true) |
end |
|
elseif isDead[guid] and not dead then |
debug(2, nameFromGUID[guid], "is now alive") |
isDead[guid] = nil |
if hasPending[guid] then |
isGhost[guid] = nil |
hasPending[guid] = nil |
debug(1, ">> ResUsed", nameFromGUID[guid]) |
callbacks:Fire("LibResInfo_ResUsed", unit, guid) |
end |
end |
end |
|
------------------------------------------------------------------------ |
|
eventFrame:Hide() |
|
local timer, INTERVAL = 0, 0.5 |
eventFrame:SetScript("OnUpdate", function(self, elapsed) |
timer = timer + elapsed |
if timer >= INTERVAL then |
debug(6, "Timer update") |
if not next(hasPending) then |
debug(4, "Nobody pending, stop timer") |
return self:Hide() |
end |
local now = GetTime() |
for guid, endTime in pairs(hasPending) do |
if endTime - now < INTERVAL then -- It will expire before the next update. |
local unit = unitFromGUID[guid] |
hasPending[guid] = nil |
debug(1, ">> ResExpired", nameFromGUID[guid]) |
callbacks:Fire("LibResInfo_ResExpired", unit, guid, true) |
end |
end |
timer = 0 |
end |
end) |
|
eventFrame:SetScript("OnShow", function() |
debug(4, "Timer start") |
end) |
|
eventFrame:SetScript("OnHide", function() |
debug(4, "Timer stop") |
timer = 0 |
end) |
|
------------------------------------------------------------------------ |
|
SLASH_LIBRESINFO1 = "/lri" |
SlashCmdList.LIBRESINFO = function(input) |
input = gsub(input, "[^A-Za-z0-9]", "") |
if strlen(input) < 1 then return end |
if strmatch(input, "%D") then |
local f = _G[input] |
if type(f) == "table" and type(f.AddMessage) == "function" then |
DEBUG_FRAME = f |
debug(0, "Debug frame set to", input) |
else |
debug(0, input, "is not a valid debug output frame!") |
end |
else |
local v = tonumber(input) |
if v and v >= 0 then |
DEBUG_LEVEL = v |
debug(0, "Debug level set to", input) |
else |
debug(0, input, "is not a valid debug level!") |
end |
end |
end |