Puppeteer/Puppeteer.lua
OldManAlpha 8a347157f7 Throttle group updates
Hopefully this doesn't break everything
2025-08-07 10:56:37 -07:00

836 lines
28 KiB
Lua

Puppeteer = {}
PTUtil.SetEnvironment(Puppeteer)
local _G = getfenv(0)
_G.PuppeteerLib = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0")
VERSION = GetAddOnMetadata("Puppeteer", "version")
TestUI = false
Banzai = AceLibrary("Banzai-1.0")
HealComm = AceLibrary("HealComm-1.0")
GuidRoster = nil -- Will be nil if SuperWoW isn't present
local compost = AceLibrary("Compost-2.0")
local util = PTUtil
local colorize = util.Colorize
local GetKeyModifier = util.GetKeyModifier
local GetClass = util.GetClass
local GetPowerType = util.GetPowerType
local UseItem = util.UseItem
local GetItemCount = util.GetItemCount
PartyUnits = util.PartyUnits
PetUnits = util.PetUnits
TargetUnits = util.TargetUnits
RaidUnits = util.RaidUnits
RaidPetUnits = util.RaidPetUnits
AllUnits = util.AllUnits
AllUnitsSet = util.AllUnitsSet
AllCustomUnits = util.CustomUnits
AllCustomUnitsSet = util.CustomUnitsSet
ReadableButtonMap = {
["LeftButton"] = "Left",
["MiddleButton"] = "Middle",
["RightButton"] = "Right",
["Button4"] = "Button 4",
["Button5"] = "Button 5"
}
ResurrectionSpells = {
["PRIEST"] = "Resurrection",
["PALADIN"] = "Redemption",
["SHAMAN"] = "Ancestral Spirit",
["DRUID"] = "Rebirth"
}
local ptBarsPath = util.GetAssetsPath().."textures\\bars\\"
BarStyles = {
["Blizzard"] = "Interface\\TargetingFrame\\UI-StatusBar",
["Blizzard Smooth"] = ptBarsPath.."Blizzard-Smooth",
["Blizzard Raid"] = ptBarsPath.."Blizzard-Raid",
["Blizzard Raid Sideless"] = ptBarsPath.."Blizzard-Raid-Sideless",
["Puppeteer"] = ptBarsPath.."Puppeteer",
["Puppeteer Borderless"] = ptBarsPath.."Puppeteer-Borderless",
["Puppeteer Shineless"] = ptBarsPath.."Puppeteer-Shineless",
["Puppeteer Shineless Borderless"] = ptBarsPath.."Puppeteer-Shineless-Borderless"
}
GameTooltip = CreateFrame("GameTooltip", "PTGameTooltip", UIParent, "GameTooltipTemplate")
CurrentlyHeldButton = nil
-- An unmapped array of all unit frames
AllUnitFrames = {}
-- A map of units to an array of unit frames associated with the unit
PTUnitFrames = {}
-- Key: Unit frame group name | Value: The group
UnitFrameGroups = {}
CustomUnitGUIDMap = PTUnitProxy and PTUnitProxy.CustomUnitGUIDMap or {}
GUIDCustomUnitMap = PTUnitProxy and PTUnitProxy.GUIDCustomUnitMap or {}
CurrentlyInRaid = false
Mouseover = nil
-- Returns the array of unit frames of the unit
function GetUnitFrames(unit)
return PTUnitFrames[unit]
end
-- A temporary dummy function while the addon initializes. See below for the real iterator.
function UnitFrames(unit)
return function() end
end
local function OpenUnitFramesIterator()
-- UnitFrames function definition.
-- Returns an iterator for the unit frames of the unit.
-- These iterators have a serious problem in that they do not support concurrent iteration.
if util.IsSuperWowPresent() then
local EMPTY_UIS = {}
local PTUnitFrames = PTUnitFrames
local GuidUnitMap = PTGuidRoster.GuidUnitMap
local iterTable = {} -- The table reused for iteration over GUID units
local uis
local i = 0
local len = 0
local iterFunc = function()
i = i + 1
if i <= len then
return uis[i]
end
end
function UnitFrames(unit)
if i < len then
print("Collision: "..i.."/"..len)
end
if GuidUnitMap[unit] then -- If a GUID is provided, ALL UIs associated with that GUID will be iterated
uis = iterTable
for i = 1, table.getn(uis) do
uis[i] = nil
end
table.setn(uis, 0)
for _, unit in pairs(GuidUnitMap[unit]) do
for _, frame in ipairs(PTUnitFrames[unit]) do
table.insert(uis, frame)
end
end
else
uis = PTUnitFrames[unit] or EMPTY_UIS
end
len = table.getn(uis)
i = 0
return iterFunc
end
else -- Optimized version for vanilla
local PTUnitFrames = PTUnitFrames
local uis
local i = 0
local len = 0
local iterFunc = function()
i = i + 1
if i <= len then
return uis[i]
end
end
function UnitFrames(unit)
i = 0
uis = PTUnitFrames[unit]
len = table.getn(uis)
return iterFunc
end
end
end
function Debug(msg)
DEFAULT_CHAT_FRAME:AddMessage(msg)
end
function UpdateUnitFrameGroups()
for _, group in pairs(UnitFrameGroups) do
group:UpdateUIPositions()
end
end
function UpdateAllIncomingHealing()
if PTHealPredict then
for _, ui in ipairs(AllUnitFrames) do
if PTOptions.UseHealPredictions then
local _, guid = UnitExists(ui:GetUnit())
ui:SetIncomingHealing(PTHealPredict.GetIncomingHealing(guid))
else
ui:SetIncomingHealing(0)
end
end
else
for _, ui in ipairs(AllUnitFrames) do
if PTOptions.UseHealPredictions then
ui:UpdateIncomingHealing()
else
ui:SetIncomingHealing(0)
end
end
end
end
function UpdateAllOutlines()
for _, ui in ipairs(AllUnitFrames) do
ui:UpdateOutline()
end
end
function CreateUnitFrameGroup(groupName, environment, units, petGroup, profile, sortByRole)
if UnitFrameGroups[groupName] then
error("[Puppeteer] Tried to create a unit frame group using existing name! \""..groupName.."\"")
return
end
local uiGroup = PTUnitFrameGroup:New(groupName, environment, units, petGroup, profile, sortByRole)
for _, unit in ipairs(units) do
local ui = PTUnitFrame:New(unit, AllCustomUnitsSet[unit] ~= nil)
if not PTUnitFrames[unit] then
PTUnitFrames[unit] = {}
end
table.insert(PTUnitFrames[unit], ui)
table.insert(AllUnitFrames, ui)
uiGroup:AddUI(ui)
if unit ~= "target" then
ui:Hide()
end
end
UnitFrameGroups[groupName] = uiGroup
return uiGroup
end
local function initUnitFrames()
local getSelectedProfile = PuppeteerSettings.GetSelectedProfile
CreateUnitFrameGroup("Party", "party", PartyUnits, false, getSelectedProfile("Party"))
CreateUnitFrameGroup("Pets", "party", PetUnits, true, getSelectedProfile("Pets"))
CreateUnitFrameGroup("Raid", "raid", RaidUnits, false, getSelectedProfile("Raid"))
CreateUnitFrameGroup("Raid Pets", "raid", RaidPetUnits, true, getSelectedProfile("Raid Pets"))
CreateUnitFrameGroup("Target", "all", TargetUnits, false, getSelectedProfile("Target"), false)
if util.IsSuperWowPresent() then
CreateUnitFrameGroup("Focus", "all", PTUnitProxy.CustomUnitsMap["focus"], false, getSelectedProfile("Focus"), false)
end
local baseCondition = UnitFrameGroups["Target"].ShowCondition
UnitFrameGroups["Target"].ShowCondition = function(self)
local friendly = not UnitCanAttack("player", "target")
return (PTOptions.AlwaysShowTargetFrame or (UnitExists("target") and
(friendly and PTOptions.ShowTargets.Friendly) or (not friendly and PTOptions.ShowTargets.Hostile)))
and baseCondition(self)
end
OpenUnitFramesIterator()
end
function OnAddonLoaded()
StartTiming("OnLoad")
if PTBindings == nil then
-- Create default bindings
_G.PTBindings = {}
PTBindings["SelectedLoadout"] = "Default"
local loadouts = {}
PTBindings["Loadouts"] = loadouts
loadouts["Default"] = CreateEmptyBindingsLoadout()
local friendlyOrHostile = "Friendly"
local modifier
local function setContext(a, b)
friendlyOrHostile = a
modifier = b
end
local function setBinding(button, binding)
local bindings = GetBindings()
local l1 = bindings.Bindings[friendlyOrHostile]
if not l1 then
l1 = {}
bindings.Bindings[friendlyOrHostile] = l1
end
local l2 = l1[modifier]
if not l2 then
l2 = {}
l1[modifier] = l2
end
l2[button] = binding
end
local function setSpell(button, spell)
setBinding(button, {Type = "SPELL", Data = spell})
end
local function setBestSpell(button, spells)
local selected
for _, spell in ipairs(spells) do
if util.GetSpellID(spell) then
selected = spell
break
end
end
if not selected then
return
end
setSpell(button, selected)
end
local function setMulti(button, tooltip, spells)
local bindings = {}
for i, spell in ipairs(spells) do
bindings[i] = {Type = "SPELL", Data = spell}
end
setBinding(button, {
Type = "MULTI",
Tooltip = {
Type = "CUSTOM",
Data = tooltip
},
Data = {
Bindings = bindings
}
})
end
local function setAction(button, action)
setBinding(button, {Type = "ACTION", Data = action})
end
local function addHealerControls()
setContext("Friendly", "Shift")
setAction("LeftButton", "Target")
setAction("MiddleButton", "Role")
setAction("RightButton", "Menu")
end
local class = GetClass("player")
if class == "PRIEST" then
setContext("Friendly", "None")
setSpell("LeftButton", "Power Word: Shield")
setSpell("MiddleButton", "Renew")
setBestSpell("RightButton", {"Greater Heal", "Heal", "Lesser Heal"})
addHealerControls()
setContext("Friendly", "Control")
setMulti("LeftButton", "Buffs", {"Power Word: Fortitude", "Divine Spirit", "Shadow Protection"})
setBinding("RightButton", "Dispel Magic")
setContext("Hostile", "None")
setSpell("RightButton", "Dispel Magic")
setContext("Hostile", "Control")
setSpell("RightButton", "Dispel Magic")
elseif class == "DRUID" then
setContext("Friendly", "None")
setSpell("LeftButton", "Rejuvenation")
setSpell("RightButton", "Healing Touch")
addHealerControls()
setContext("Friendly", "Control")
setSpell("RightButton", "Remove Curse")
elseif class == "PALADIN" then
setContext("Friendly", "None")
setSpell("LeftButton", "Flash of Light")
setSpell("RightButton", "Holy Light")
addHealerControls()
setContext("Friendly", "Control")
setMulti("LeftButton", "Blessings", {"Blessing of Might", "Blessing of Wisdom", "Blessing of Salvation", "Blessing of Kings"})
setBestSpell("RightButton", {"Cleanse", "Purify"})
elseif class == "SHAMAN" then
setContext("Friendly", "None")
setBestSpell("LeftButton", {"Healing Wave", "Lesser Healing Wave"})
setSpell("RightButton", "Chain Heal")
addHealerControls()
setContext("Friendly", "Control")
setSpell("RightButton", "Cure Disease")
else
-- Non-healer classes can use this addon like traditional raid frames
setContext("Friendly", "None")
setAction("LeftButton", "Target")
setAction("MiddleButton", "Role")
setAction("RightButton", "Menu")
setContext("Hostile", "None")
setAction("LeftButton", "Target")
setAction("RightButton", "Menu")
end
end
PuppeteerSettings.SetDefaults()
SetupSpecialButtons()
InitBindingDisplayCache()
if util.IsSuperWowPresent() then
-- In case other addons override unit functions, we want to make sure we're using their functions
PTUnitProxy.CreateUnitProxies()
-- Do it again after all addons have loaded
local frame = CreateFrame("Frame")
local reapply = GetTime() + 0.1
frame:SetScript("OnUpdate", function()
if GetTime() > reapply then
PTUnitProxy.CreateUnitProxies()
frame:SetScript("OnUpdate", nil)
end
end)
end
if not _G.PTRoleCache then
_G.PTRoleCache = {}
end
if not _G.PTRoleCache[GetRealmName()] then
_G.PTRoleCache[GetRealmName()] = {}
end
AssignedRoles = _G.PTRoleCache[GetRealmName()]
PruneAssignedRoles()
if util.IsSuperWowPresent() then
PTUnit.UpdateGuidCaches()
local customUnitUpdater = CreateFrame("Frame", "PTCustomUnitUpdater")
local nextUpdate = GetTime() + 0.25
-- Older versions of SuperWoW had an issue where units that aren't part of normal units wouldn't receive events,
-- so updates are done manually
local needsManualUpdates = util.SuperWoWFeatureLevel < util.SuperWoW_v1_4
customUnitUpdater:SetScript("OnUpdate", function()
if GetTime() > nextUpdate then
nextUpdate = GetTime() + 0.25
for unit, guid in pairs(CustomUnitGUIDMap) do
if needsManualUpdates or not UnitExists(guid) then
PTUnit.Get(unit):UpdateAuras()
for ui in UnitFrames(unit) do
ui:UpdateHealth()
ui:UpdatePower()
ui:UpdateAuras()
ui:UpdateIncomingHealing()
end
end
end
end
end)
else
PTUnit.CreateCaches()
end
PuppeteerSettings.UpdateTrackedDebuffTypes()
PTProfileManager.InitializeDefaultProfiles()
do
if PTOptions.Scripts.OnLoad then
local scriptString = "local GetProfile = PTProfileManager.GetProfile "..
"local CreateProfile = PTProfileManager.CreateProfile "..PTOptions.Scripts.OnLoad
local script, err = loadstring(scriptString)
if script then
local ok, result = pcall(script)
if not ok then
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] ", 1, 0.4, 0.4)..colorize("ERROR: ", 1, 0.2, 0.2)
..colorize("The Load Script produced an error! If this causes Puppeteer to fail to load, "..
"you will need to manually edit the script in your game files.", 1, 0.4, 0.4))
DEFAULT_CHAT_FRAME:AddMessage(colorize("OnLoad Script Error: "..tostring(result), 1, 0, 0))
end
else
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] ", 1, 0.4, 0.4)..colorize("ERROR: ", 1, 0.2, 0.2)
..colorize("The Load Script failed to load: "..err, 1, 0.4, 0.4))
end
end
end
PTSettingsGui.Init()
if PTHealPredict then
PTHealPredict.OnLoad()
PTHealPredict.HookUpdates(function(guid, incomingHealing, incomingDirectHealing)
if not PTOptions.UseHealPredictions then
return
end
local units = GuidRoster.GetUnits(guid)
if not units then
return
end
for _, unit in ipairs(units) do
for ui in UnitFrames(unit) do
ui:SetIncomingHealing(incomingHealing, incomingDirectHealing)
end
end
end)
else
local roster = AceLibrary("RosterLib-2.0")
PuppeteerLib:RegisterEvent("HealComm_Healupdate", function(name)
if not PTOptions.UseHealPredictions then
return
end
local unit = roster:GetUnitIDFromName(name)
if unit then
for ui in UnitFrames(unit) do
ui:UpdateIncomingHealing()
end
end
if UnitName("target") == name then
for ui in UnitFrames("target") do
ui:UpdateIncomingHealing()
end
end
end)
PuppeteerLib:RegisterEvent("HealComm_Ressupdate", function(name)
local unit = roster:GetUnitIDFromName(name)
if unit then
for ui in UnitFrames(unit) do
ui:UpdateHealth()
end
end
if UnitName("target") == name then
for ui in UnitFrames("target") do
ui:UpdateHealth()
end
end
end)
end
SetLFTAutoRoleEnabled(PTOptions.LFTAutoRole)
TestUI = PTOptions.TestUI
if TestUI then
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] UI Testing is enabled. Use /pt testui to disable.", 1, 0.6, 0.6))
end
initUnitFrames()
StartDistanceScanner()
PuppeteerLib:RegisterEvent("Banzai_UnitGainedAggro", function(unit)
if PTGuidRoster then
unit = PTGuidRoster.GetUnitGuid(unit)
end
for ui in UnitFrames(unit) do
ui:UpdateOutline()
end
end)
PuppeteerLib:RegisterEvent("Banzai_UnitLostAggro", function(unit)
if PTGuidRoster then
unit = PTGuidRoster.GetUnitGuid(unit)
end
for ui in UnitFrames(unit) do
ui:UpdateOutline()
end
end)
if PTOnLoadInfoDisabled == nil then
PTOnLoadInfoDisabled = false
end
do
local INFO_SEND_TIME = GetTime() + 0.5
local infoFrame = CreateFrame("Frame")
infoFrame:SetScript("OnUpdate", function()
if GetTime() < INFO_SEND_TIME then
return
end
infoFrame:SetScript("OnUpdate", nil)
if not PTOnLoadInfoDisabled then
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] Use ", 0.5, 1, 0.5)..colorize("/pt help", 0, 1, 0)
..colorize(" to see commands.", 0.5, 1, 0.5))
end
if not util.IsSuperWowPresent() and util.IsNampowerPresent() then
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] ", 1, 0.4, 0.4)..colorize("WARNING: ", 1, 0.2, 0.2)
..colorize("You are using Nampower without SuperWoW, which will cause heal predictions to be wildly inaccurate "..
"for you and your raid members! It is highly recommended to install SuperWoW.", 1, 0.4, 0.4))
end
if util.IsSuperWowPresent() and not HealComm:IsEventRegistered("UNIT_CASTEVENT") then
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] ", 1, 0.4, 0.4)..colorize("WARNING: ", 1, 0.2, 0.2)
..colorize("You have another addon that uses a HealComm version that is incompatible with SuperWoW! "..
"This will cause wildly inaccurate heal predictions to be shown to your raid members. It is "..
"recommended to either unload the offending addon or copy Puppeteer's HealComm "..
"into the other addon.", 1, 0.4, 0.4))
end
end)
end
do
if PTOptions.Scripts.OnPostLoad then
local scriptString = PTOptions.Scripts.OnPostLoad
local script, err = loadstring(scriptString)
if script then
local ok, result = pcall(script)
if not ok then
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] ", 1, 0.4, 0.4)..colorize("ERROR: ", 1, 0.2, 0.2)
..colorize("The Postload Script produced an error! If this causes Puppeteer to fail to operate, "..
"you may need to manually edit the script in your game files.", 1, 0.4, 0.4))
DEFAULT_CHAT_FRAME:AddMessage(colorize("OnPostLoad Script Error: "..tostring(result), 1, 0, 0))
end
else
DEFAULT_CHAT_FRAME:AddMessage(colorize("[Puppeteer] ", 1, 0.4, 0.4)..colorize("ERROR: ", 1, 0.2, 0.2)
..colorize("The Postload Script failed to load: "..err, 1, 0.4, 0.4))
end
end
end
EndTiming("OnLoad")
end
function CheckPartyFramesEnabled()
local shouldBeDisabled = (CurrentlyInRaid and PTOptions.DisablePartyFrames.InRaid) or
(not CurrentlyInRaid and PTOptions.DisablePartyFrames.InParty)
SetPartyFramesEnabled(not shouldBeDisabled)
end
function SetPartyFramesEnabled(enabled)
if enabled then
for i = 1, MAX_PARTY_MEMBERS do
local frame = getglobal("PartyMemberFrame"..i)
if frame and frame.PTRealShow then
frame.Show = frame.PTRealShow
frame.PTRealShow = nil
if UnitExists("party"..i) then
frame:Show()
end
local prevThis = _G.this
_G.this = frame
PartyMemberFrame_OnLoad()
_G.this = prevThis
end
end
else
for i = 1, MAX_PARTY_MEMBERS do
local frame = getglobal("PartyMemberFrame"..i)
if frame and not frame.PTRealShow then
frame:UnregisterAllEvents()
frame.PTRealShow = frame.Show
frame.Show = function() end
frame:Hide()
end
end
end
end
function _G.PT_ToggleFocusUnit(unit)
if PTUnitProxy.IsUnitUnitType(unit, "focus") then
if not PTUnitProxy.CustomUnitsSetMap["focus"][unit] then
return -- Do not toggle focus if user is clicking on a UI that isn't the focus UI
end
PT_UnfocusUnit(unit)
else
PT_FocusUnit(unit)
end
end
function _G.PT_FocusUnit(unit)
local guid = PTGuidRoster.ResolveUnitGuid(unit)
if not guid or PTUnitProxy.IsGuidUnitType(guid, "focus") then
return
end
PTUnitProxy.SetGuidUnitType(guid, "focus")
PlaySound("GAMETARGETHOSTILEUNIT")
end
function _G.PT_UnfocusUnit(unit)
local guid = PTGuidRoster.ResolveUnitGuid(unit)
if not guid then
return
end
local focusUnit = PTUnitProxy.GetCurrentUnitOfType(guid, "focus")
if not focusUnit then
return
end
PTUnitProxy.SetCustomUnitGuid(focusUnit, nil)
PlaySound("INTERFACESOUND_LOSTTARGETUNIT")
end
function _G.PT_PromoteFocus(unit)
local guid = PTGuidRoster.ResolveUnitGuid(unit)
if not guid then
return
end
PTUnitProxy.PromoteGuidUnitType(guid, "focus")
end
function CycleFocus(onlyAttackable)
PTUnitProxy.CycleUnitType("focus", onlyAttackable)
end
local emptySpell = {}
function UnitFrame_OnClick(button, unit, unitFrame)
if not UnitExists(unit) then
return
end
local binding = GetBindingFor(unit, GetKeyModifier(), button)
local targetCastable = UnitIsConnected(unit) and UnitIsVisible(unit)
local wantToRes = PTOptions.AutoResurrect and util.IsDeadFriend(unit) and ResurrectionSpells[GetClass("player")]
if not binding then
if targetCastable and wantToRes then
RunBinding_Spell(emptySpell, unit)
end
return
end
RunBinding(binding, unit, unitFrame)
end
local CheckGroupThrottler = CreateFrame("Frame", "PTCheckGroupThrottler")
local MAX_GROUP_UPDATE_TOKENS = 2
local GROUP_UPDATE_RECOVERY = 0.1
local groupUpdateTokens = 2
local nextGroupUpdateToken = 0
local groupUpdateWaiting = false
local CheckGroupThrottler_OnUpdate = function()
if nextGroupUpdateToken <= GetTime() then
groupUpdateTokens = groupUpdateTokens + 1
nextGroupUpdateToken = GetTime() + GROUP_UPDATE_RECOVERY
if groupUpdateWaiting then
groupUpdateWaiting = false
print("Delayed Group Update")
CheckGroupThrottled()
end
if groupUpdateTokens == MAX_GROUP_UPDATE_TOKENS then
CheckGroupThrottler:SetScript("OnUpdate", nil)
end
end
end
function UseGroupUpdateToken()
if groupUpdateTokens > 0 then
groupUpdateTokens = groupUpdateTokens - 1
if CheckGroupThrottler:GetScript("OnUpdate") == nil then
nextGroupUpdateToken = GetTime() + GROUP_UPDATE_RECOVERY
CheckGroupThrottler:SetScript("OnUpdate", CheckGroupThrottler_OnUpdate)
end
return true
end
groupUpdateWaiting = true
return false
end
-- Same as CheckGroup, but may delay and consolidate checks if there's been many calls
function CheckGroupThrottled()
if UseGroupUpdateToken() then
CheckGroup()
print("Group Update "..groupUpdateTokens)
else
print("GROUP UPDATE THROTTLED")
end
end
-- Reevaluates what UI frames should be shown and updates the roster if using SuperWoW
function CheckGroup()
StartTiming("CheckGroup")
if GetNumRaidMembers() > 0 then
if not CurrentlyInRaid then
CurrentlyInRaid = true
SetPartyFramesEnabled(not PTOptions.DisablePartyFrames.InRaid)
end
else
if CurrentlyInRaid then
CurrentlyInRaid = false
SetPartyFramesEnabled(not PTOptions.DisablePartyFrames.InParty)
end
end
local superwow = util.IsSuperWowPresent()
if superwow then
GuidRoster.ResetRoster()
GuidRoster.PopulateRoster()
PTUnit.UpdateGuidCaches()
end
for _, unit in ipairs(util.AllRealUnits) do
local exists, guid = UnitExists(unit)
if unit ~= "target" then
if exists then
for ui in UnitFrames(unit) do
ui:Show()
end
else
for ui in UnitFrames(unit) do
ui:Hide()
end
end
end
end
for _, group in pairs(UnitFrameGroups) do
group:EvaluateShown()
end
if not superwow then -- If SuperWoW isn't present, the units may have shifted and thus require a full scan
PTUnit.UpdateAllUnits()
end
for _, ui in pairs(AllUnitFrames) do
if ui:IsShown() then
ui:UpdateRange()
ui:UpdateAuras()
ui:UpdateIncomingHealing()
ui:UpdateOutline()
end
end
if superwow then
PTHealPredict.SetRelevantGUIDs(GuidRoster.GetTrackedGuids())
end
RunTrackingScan()
EndTiming("CheckGroup")
end
function CheckTarget()
local exists, guid = UnitExists("target")
if exists then
local friendly = not UnitCanAttack("player", "target")
if (friendly and PTOptions.ShowTargets.Friendly) or (not friendly and PTOptions.ShowTargets.Hostile) then
for ui in UnitFrames("target") do
ui.lastHealthPercent = (ui:GetCurrentHealth() / ui:GetMaxHealth()) * 100
ui:UpdateRange()
ui:UpdateSight()
ui:UpdateRole()
ui:UpdateIncomingHealing()
end
end
else
for ui in UnitFrames("target") do
ui.lastHealthPercent = (ui:GetCurrentHealth() / ui:GetMaxHealth()) * 100
ui:UpdateAll()
ui:UpdateRole()
ui:UpdateIncomingHealing()
end
end
UnitFrameGroups["Target"]:EvaluateShown()
end
function IsRelevantUnit(unit)
return AllUnitsSet[unit] ~= nil or GUIDCustomUnitMap[unit]
end
function print(msg)
if not PTOptions or not PTOptions["Debug"] then
return
end
local window
local i = 1
while not window do
local name = GetChatWindowInfo(i)
if not name then
break
end
if name == "Debug" then
window = getglobal("ChatFrame"..i)
break
end
i = i + 1
end
if window then
window:AddMessage(tostring(msg))
end
end
function StartTiming(name)
if not pfDebug_StartTiming then
return
end
pfDebug_StartTiming(name)
end
function EndTiming(name)
if not pfDebug_EndTiming then
return
end
pfDebug_EndTiming(name)
end