7 Commits
Author SHA1 Message Date
Brues bea2cedc08 buffwatch: use official dispel-type colours for debuff bars
The debuff-bar auto colour read the vanilla DebuffTypeColor global,
diverging from unitframes/buff which use C_UnitAuras.GetAuraDispelTypeColor
(the BC GlobalColor.dbc palette ClassicAPI ships). Switch buffwatch to the
same accessor so all aura displays share one palette; nil/unknown types
fall back to DEBUFF_TYPE_NONE instead of the old ad-hoc (1, .2, .2).
2026-08-23 13:25:06 -05:00
Brues 23c783622c buff/buffwatch: positional aura reads in hot refresh loops
buff.lua RefreshBuffButton runs 50x per PLAYER_AURAS_CHANGED and
buffwatch.lua GetBuffData runs 32x per RefreshBuffBarFrame; both now use
the zero-allocation positional C_UnitAuras.UnitAura instead of the
table-allocating GetAuraDataByIndex.

buffwatch also threads the aura's dispelType out of GetBuffData onto the
frame.buffs row, so the debuff-bar colour reads it from the row instead
of re-fetching the aura with GetDebuffDataByIndex on every name change.

Cold single-lookups (hover/click tooltips) keep the readable table API.
2026-08-23 13:05:42 -05:00
Brues 3cb52618a9 unitframes: scan debuff slots once for dispel indicators
The dispellable-indicator block re-scanned all 16 harmful slots for
every dispellable type (O(types x 16) UnitDebuff calls per refresh).
Scan the 16 slots once into a reusable set, then have the per-type loop
check the set. Zero-allocation (the set is cleared and reused within the
single RefreshUnit call).
2026-08-23 13:05:29 -05:00
Brues 461ad22a57 Use positional C_UnitAuras accessors in hot aura scans
Swap the per-frame aura-refresh loops from table-allocating
GetAuraDataByIndex/GetBuffDataByIndex/GetDebuffDataByIndex/GetUnitAuras
to the zero-allocation positional C_UnitAuras.UnitAura/UnitBuff/UnitDebuff.

unitframes: buff/debuff icon loops, the dispellable-indicator 16-slot
scan, the two GetUnitAuras indicator passes, and the custom-debuff scan.
nameplates: the per-plate debuff scan now writes positional results
straight into the reusable display buffer, dropping the per-aura tables
and the result array.

Filters change from HARMFUL|PLAYER/HARMFUL to PLAYER/nil since UnitBuff/
UnitDebuff lock the range and still honor the PLAYER predicate. Cold
single-lookups (hover/click, tooltip, totem icon, libdebuff) keep the
readable table API.
2026-08-23 12:53:56 -05:00
Brues 10b028b0c2 Bump ClassicAPI minimum version 2026-08-21 15:00:25 -05:00
Brues 7ccc56c241 utlize inline icons and CreateGoldString in repair module 2026-08-21 15:00:25 -05:00
Brues c64a501e6f Utilize SetFormattedText
This change updates several text setters to use `SetFormattedText` instead of passing `string.format(...)` into `SetText`. It also switches a few regex captures from `string.find` to `string.match` for cleaner capture handling, and replaces explicit width/height setters with `SetSize` in the first-run dialog for consistency.
2026-08-21 15:00:25 -05:00
3 changed files with 100 additions and 35 deletions
-3
View File
@@ -168,9 +168,6 @@ pfUI.libdebuff_spell_start_self_hooks["libpredict"] = function(spellId, casterGu
return
end
spell_queue[1] = spellName
spell_queue[2] = spellName .. (C_Spell.GetSpellSubtext(spellId) or "")
if spell_queue[1] == spellName and cache[spell_queue[2]] then
local amount = cache[spell_queue[2]][1]
local casttime = castTime
+90 -23
View File
@@ -3,15 +3,56 @@ pfUI:RegisterModule("tracking", function ()
MINIMAP_TRACKING_FRAME:UnregisterAllEvents()
MINIMAP_TRACKING_FRAME:Hide()
local function HasEntries(tbl)
for _ in pairs(tbl) do
return true
end
return nil
end
local rawborder, border = GetBorderSize()
local size = tonumber(C.appearance.minimap.tracking_size)
local pulse = C.appearance.minimap.tracking_pulse == "1"
-- Tracking spells come from ClassicAPI's native GetNumTrackingTypes /
-- GetTrackingInfo (see the DLL's docs/API.md "Tracking"). The DLL
-- enumerates them straight from the spellbook by tracking-aura effect,
-- so there is no spell table to maintain here and server-custom trackers
-- (e.g. Turtle's Find Trees) are picked up automatically.
-- Tracking spells identified by SpellID + expected icon path.
-- SpellID is the primary identifier (stable, locale-independent).
-- Icon path is used as secondary confirmation when scanning the spellbook.
local knownTrackingSpells = {
any = {
{ id = 2481, icon = "Racial_Dwarf_FindTreasure" }, -- Find Treasure
{ id = 2580, icon = "Spell_Nature_Earthquake" }, -- Find Minerals
{ id = 2383, icon = "INV_Misc_Flower_02" }, -- Find Herbs (Rank 1)
{ id = 8387, icon = "INV_Misc_Flower_02" }, -- Find Herbs (Rank 2)
{ id = 52917, icon = "INV_TradeSkillItem_03" }, -- Find Trees (TurtleWow)
},
HUNTER = {
{ id = 1494, icon = "Ability_Tracking" }, -- Track Beasts
{ id = 19883, icon = "Spell_Holy_PrayerOfHealing" }, -- Track Humanoids
{ id = 19884, icon = "Spell_Shadow_DarkSummoning" }, -- Track Undead
{ id = 19885, icon = "Ability_Stealth" }, -- Track Hidden
{ id = 19880, icon = "Spell_Frost_SummonWaterElemental" }, -- Track Elementals
{ id = 19878, icon = "Spell_Shadow_SummonFelHunter" }, -- Track Demons
{ id = 19882, icon = "Ability_Racial_Avatar" }, -- Track Giants
{ id = 19879, icon = "INV_Misc_Head_Dragon_01" }, -- Track Dragonkin
},
PALADIN = {
{ id = 5502, icon = "Spell_Holy_SenseUndead" }, -- Sense Undead
},
WARLOCK = {
{ id = 5500, icon = "Spell_Shadow_Metamorphosis" }, -- Sense Demons
},
DRUID = {
{ id = 5225, icon = "Ability_Tracking" }, -- Track Humanoids (Cat Form only)
},
}
-- Build a flat lookup: spellId -> entry, for fast spellbook matching
local spellIdLookup = {}
for _, entries in pairs(knownTrackingSpells) do
for _, entry in ipairs(entries) do
spellIdLookup[entry.id] = entry
end
end
local state = {
texture = nil,
@@ -87,24 +128,50 @@ pfUI:RegisterModule("tracking", function ()
end)
function pfUI.tracking:RefreshSpells()
state.spells = {}
if not GetNumTrackingTypes then return end
local playerClass = UnitClassBase("player")
local isCatForm = pfUI.tracking:PlayerIsDruidInCatForm(playerClass)
-- Druid Track Humanoids (5225) only casts in Cat Form. Hide it out of
-- form so the menu never offers a tracker that would fail to cast.
local isCatForm = pfUI.tracking:PlayerIsDruidInCatForm(UnitClassBase("player"))
-- Build set of valid SpellIDs for this class
local validIds = {}
for _, entry in ipairs(knownTrackingSpells.any) do
validIds[entry.id] = true
end
if knownTrackingSpells[playerClass] then
for _, entry in ipairs(knownTrackingSpells[playerClass]) do
validIds[entry.id] = true
end
end
for i = 1, GetNumTrackingTypes() do
local name, texture, _, _, spellId = GetTrackingInfo(i)
local castable = not (spellId == 5225 and not isCatForm)
if name and texture and castable
and not pfUI.tracking.invalidSpells[name] then
state.spells[i] = {
index = i, -- tracking index, passed to SetTracking()
name = name,
texture = texture,
spellId = spellId,
}
-- Druids only get Track Humanoids in Cat Form
if playerClass == "DRUID" and not isCatForm then
validIds[5225] = nil
end
-- Scan spellbook: match by icon path, confirm SpellID is valid for this class
for tabIndex = 1, GetNumSpellTabs() do
local _, _, offset, numSpells = GetSpellTabInfo(tabIndex)
for spellIndex = offset + 1, offset + numSpells do
local spellTexture = GetSpellTexture(spellIndex, BOOKTYPE_SPELL)
local spellName = GetSpellName(spellIndex, BOOKTYPE_SPELL)
if pfUI.tracking.invalidSpells[spellName] then
spellTexture = nil
end
if spellTexture then
local lowerTexture = string.lower(spellTexture)
for spellId, entry in pairs(spellIdLookup) do
if validIds[spellId] and not state.spells[spellId]
and strfind(lowerTexture, string.lower(entry.icon)) then
state.spells[spellId] = {
index = spellIndex,
name = spellName,
texture = spellTexture,
spellId = spellId,
}
end
end
end
end
end
end
@@ -120,7 +187,7 @@ pfUI:RegisterModule("tracking", function ()
elseif not texture then
state.texture = nil
if pulse and next(state.spells) ~= nil then
if pulse and HasEntries(state.spells) then
pfUI.tracking.pulse = true
pfUI.tracking.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
pfUI.tracking.icon:SetVertexColor(1,1,1,1)
@@ -150,7 +217,7 @@ pfUI:RegisterModule("tracking", function ()
checked = spell.texture == state.texture,
arg1 = spell,
func = function (arg1)
SetTracking(arg1.index)
CastSpell(arg1.index, BOOKTYPE_SPELL)
CloseDropDownMenus()
end
})
+10 -9
View File
@@ -23,7 +23,7 @@ do
-- ClassicAPI dependency check.
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
-- API surface that ClassicAPI polyfills, so presence is required.
local PFUI_CLASSIC_API_MIN = 11204 -- (X*10000 + Y*100 + Z)
local PFUI_CLASSIC_API_MIN = 11100 -- (X*10000 + Y*100 + Z)
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
@@ -86,13 +86,14 @@ do
end
end
pfUI_playerDB = pfUI_playerDB or {}
pfUI_config = pfUI_config or {}
pfUI_init = pfUI_init or {}
pfUI_profiles = pfUI_profiles or {}
pfUI_addon_profiles = pfUI_addon_profiles or {}
pfUI_cache = pfUI_cache or {}
pfUI_throttle = pfUI_throttle or {}
-- initialize saved variables
pfUI_playerDB = {}
pfUI_config = {}
pfUI_init = {}
pfUI_profiles = {}
pfUI_addon_profiles = {}
pfUI_cache = {}
pfUI_throttle = {}
-- localization
pfUI_locale = {}
@@ -576,4 +577,4 @@ function pfUI.SetupCVars()
COMBAT_TEXT_SHOW_HONOR_GAINED = "1"
end
UIParentLoadAddOn("Blizzard_CombatText")
end
end