8 Commits
Author SHA1 Message Date
Brues 0fa78d3812 bump CAPI min 2026-08-23 14:01:37 -05:00
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
34 changed files with 5702 additions and 5939 deletions
+3 -3
View File
@@ -23,12 +23,12 @@ jobs:
IFS=. read -r MAJOR MINOR PATCH <<<"$LATEST"
PACKED=$((MAJOR * 10000 + MINOR * 100 + PATCH))
echo "Pinning PFUI_CLASSIC_API_LATEST to $LATEST ($PACKED)"
sed -i "s/^\([[:space:]]*\)local PFUI_CLASSIC_API_LATEST = .*/\1local PFUI_CLASSIC_API_LATEST = $PACKED/" API_Check.lua
grep 'local PFUI_CLASSIC_API_' API_Check.lua
sed -i "s/^\([[:space:]]*\)local PFUI_CLASSIC_API_LATEST = .*/\1local PFUI_CLASSIC_API_LATEST = $PACKED/" pfUI.lua
grep 'local PFUI_CLASSIC_API_' pfUI.lua
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Package and release to GitHub
uses: brues-code/packager@vCAPI
uses: BigWigsMods/packager@v2
env:
GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }}
-22
View File
@@ -1,22 +0,0 @@
{
"runtime": {
"version": "Lua 5.1"
},
"diagnostics": {
"disable": ["deprecated"],
"globals": [
"this",
"event",
"arg",
"arg1",
"arg2",
"arg3",
"arg4",
"arg5",
"arg6",
"arg7",
"arg8",
"arg9"
]
}
}
-4
View File
@@ -1,4 +0,0 @@
package-as: pfUI
ignore:
- .luarc.json
-78
View File
@@ -1,78 +0,0 @@
do
-- ClassicAPI dependency gate.
--
-- Which TOC the client opened already answers "is ClassicAPI here?". Whenever
-- the DLL is loaded it redirects the read of `pfUI\pfUI.toc` to
-- `pfUI_Turtle.toc` (Turtle clients) or `pfUI_ClassicAPI.toc` (everything
-- else). Reaching this file from the plain `pfUI.toc` therefore means
-- ClassicAPI is absent -- and that TOC deliberately loads nothing but this
-- file, so there is nothing to disable, only a notice to show.
--
-- The flavor TOCs still need a version gate of their own: the redirect has
-- existed since ClassicAPI v1.11.0, well below the API surface pfUI relies
-- on. There pfUI does load, and will throw wherever it reaches for something
-- the installed DLL doesn't have yet -- the popup names the cause so those
-- errors aren't a mystery.
local PFUI_CLASSIC_API_MIN = 11304 -- (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"
local function FormatVersion(packed)
local x = math.floor(packed / 10000)
local y = math.floor(math.mod(packed, 10000) / 100)
local z = math.mod(packed, 100)
return string.format("v%d.%d.%d", x, y, z)
end
local headline, detail
if not CLASSIC_API_VERSION then
headline = "|cff33ffccpf|cffffffffUI|r has been disabled."
detail = "The ClassicAPI DLL isn't loaded. Download the latest release from:"
elseif CLASSIC_API_VERSION < PFUI_CLASSIC_API_MIN then
headline = "|cff33ffccpf|cffffffffUI|r will not work correctly on ClassicAPI " .. FormatVersion(CLASSIC_API_VERSION) .. "."
detail = FormatVersion(PFUI_CLASSIC_API_MIN) .. " or newer is required -- any errors alongside this one are the APIs it is missing. Download the latest release from:"
end
if detail then
local function ShowRequiredPopup()
StaticPopupDialogs["PFUI_CLASSICAPI_REQUIRED"] = {
text = headline .. "\n\n" .. detail,
button1 = OKAY,
hasEditBox = 1,
editBoxWidth = 280,
timeout = 0,
whileDead = 1,
hideOnEscape = 1,
preferredIndex = 3,
OnShow = function()
local editBox = getglobal(this:GetName().."EditBox")
if editBox then
editBox:SetText(PFUI_CLASSIC_API_LATEST_URL)
editBox:HighlightText()
editBox:SetFocus()
end
end,
}
StaticPopup_Show("PFUI_CLASSICAPI_REQUIRED")
DEFAULT_CHAT_FRAME:AddMessage(
headline .. " " .. detail .. " " .. PFUI_CLASSIC_API_LATEST_URL,
1, 0.3, 0.3
)
end
local loginFrame = CreateFrame("Frame")
loginFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
loginFrame:SetScript("OnEvent", function()
loginFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
ShowRequiredPopup()
end)
elseif CLASSIC_API_VERSION < PFUI_CLASSIC_API_LATEST then
EventUtil.ContinueOnPlayerLogin(function()
C_Timer.After(8, function()
DEFAULT_CHAT_FRAME:AddMessage(
"|cff33ffccpf|rUI: ClassicAPI " .. FormatVersion(PFUI_CLASSIC_API_LATEST) .. " is available — " .. PFUI_CLASSIC_API_LATEST_URL,
1, 0.85, 0.3
)
end)
end)
end
end
-59
View File
@@ -204,26 +204,6 @@ function pfUI.api.UnitHasBuff(unit, name)
return C_UnitAuras.GetAuraDataBySpellName(unit, name, "HELPFUL") ~= nil or nil
end
-- [ ScanAuraSlots ]
-- Fills `buf` with the slot ids of the auras on `unit` that match `filter` and
-- returns how many (buf[1..n]; entries past n are cleared), so a module can
-- keep one buffer and refill it every refresh. Read each aura with
-- C_UnitAuras.UnitAuraBySlot(unit, buf[i]) (positional, no table) or
-- GetAuraDataBySlot. One enumeration walks the aura array once, where a
-- by-index loop (UnitAura(unit, i)) re-walks it from the start for every i.
-- Uses GetAuraSlots' fill-a-table form (table as the 5th argument) instead of
-- its vararg return: Lua 5.0 builds an `arg` table for every vararg call, so
-- collecting the returns in a Lua helper would allocate once per scan.
-- unit [string] unit token
-- filter [string] aura filter ("HELPFUL", "HARMFUL|PLAYER", ...)
-- buf [table] reusable buffer, filled in place
-- max [number] optional cap on the slot count (nil = all)
-- return: [number] count of slot ids written to buf
function pfUI.api.ScanAuraSlots(unit, filter, buf, max)
local _, n = C_UnitAuras.GetAuraSlots(unit, filter, max, nil, buf)
return n
end
-- [ IsPlayerGuid ]
-- Returns whether a GUID or unit token refers to the local player.
-- guid [string] A unit GUID (or unitID) to test.
@@ -262,45 +242,6 @@ function pfUI.api.GetUnitColor(unitstr)
return classColor:GenerateHexColorMarkup(), classColor:GetRGB()
end
-- [ GetRaceIcon ]
-- Builds an inline race icon texture from the shared races atlas.
-- 'raceKey' [string] englishRace key (e.g. "NightElf")
-- 'sex' [int] unit sex (3 = female)
-- return: [string] inline texture escape, or an empty string
function pfUI.api.GetRaceIcon(raceKey, sex)
if not raceKey then return "" end
local gender = sex == 3 and "FEMALE" or "MALE"
local coords = RACE_ICON_TCOORDS[strupper(raceKey) .. "_" .. gender]
if not coords then return "" end
return string.format(
"|TInterface\\Glues\\CharacterCreate\\UI-CharacterCreate-Races:0:0:0:0:512:512:%d:%d:%d:%d|t",
coords[1] * 512, coords[2] * 512, coords[3] * 512, coords[4] * 512)
end
-- inline faction emblems (cropped from the target-frame PvP banners)
local FACTION_ICON = {
Alliance = "|TInterface\\TargetingFrame\\UI-PVP-Alliance:0:0:0:0:64:64:5:37:3:35|t",
Horde = "|TInterface\\TargetingFrame\\UI-PVP-Horde:0:0:0:0:64:64:5:37:3:35|t",
}
-- [ GetFactionIcon ]
-- Resolves an inline faction emblem from the englishRace key stored in L["race"].
-- 'raceKey' [string] englishRace key (e.g. "Orc")
-- return: [string] inline texture escape, or an empty string
function pfUI.api.GetFactionIcon(raceKey)
local info = raceKey and L["race"][raceKey]
if not info then return "" end
return FACTION_ICON[info.faction] or ""
end
-- [ GetPlayerRaceIcons ]
-- Returns the faction and race emblems of the player character.
-- return: [string] both inline textures, or an empty string
function pfUI.api.GetPlayerRaceIcons()
local _, raceKey = UnitRace("player")
return pfUI.api.GetFactionIcon(raceKey) .. pfUI.api.GetRaceIcon(raceKey, UnitSex("player"))
end
-- [ strvertical ]
-- Creates vertical text using linebreaks. Multibyte char friendly.
-- 'str' [string] String to columnize.
-1
View File
@@ -817,7 +817,6 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("chat", "text", "playerlinks", "1")
pfUI:UpdateConfig("chat", "text", "detecturl", "1")
pfUI:UpdateConfig("chat", "text", "classcolor", "1")
pfUI:UpdateConfig("chat", "text", "playericons", "0")
pfUI:UpdateConfig("chat", "text", "whosearchunknown", "0")
pfUI:UpdateConfig("chat", "text", "playerlevel", "0")
pfUI:UpdateConfig("chat", "left", "width", "380")
+30 -51
View File
@@ -4,17 +4,6 @@ setfenv(1, pfUI:GetEnvironment())
pfUI.uf = CreateFrame("Frame", nil, UIParent)
pfUI.uf.frames = {}
-- Reusable buffer for C_UnitAuras.GetAuraSlots slot ids (filled by
-- ScanAuraSlots, api.lua). Each aura scan in RefreshUnit fills it once, then
-- reads every aura by slot id: one array walk per scan instead of one per index.
-- Scans run back to back and consume the buffer before the next refill.
local auraSlots = {}
-- Separate buffer for the tooltip handlers. They run from OnEnter, which can
-- fire while RefreshUnit is showing/hiding icons under the cursor, so they must
-- not share the refresh buffer.
local tooltipSlots = {}
-- ============================================================================
-- GUID-based Roster Tracking for Smart Updates
-- Only updates frames where the unit actually changed, not ALL 40 frames
@@ -99,21 +88,16 @@ local function DebuffOnEnter()
local parent = this:GetParent()
-- selfdebuff filters the displayed list to player-cast harmful auras, but
-- SetUnitAura's index has to be into the unfiltered HARMFUL list. Look up
-- the displayed aura via the PLAYER filter, then find its position in the
-- unfiltered list by name + sourceGUID.
--
-- The unfiltered list is NOT capped at 16: once a unit's 16 debuff slots
-- are full the server parks further debuffs in buff slots, and C_UnitAuras
-- reports those as harmful too. So enumerate however many the unit has.
-- SetUnitAura's index has to be into the engine's full HARMFUL list. Look
-- up the displayed aura via the PLAYER filter, then scan engine slots for
-- one whose name + sourceGUID match.
if parent.config and parent.config.selfdebuff == "1" then
local ownAura = C_UnitAuras.GetAuraDataByIndex(unitstr, this.id, "HARMFUL|PLAYER")
if ownAura then
local n = ScanAuraSlots(unitstr, "HARMFUL", tooltipSlots)
for i = 1, n do
local check = C_UnitAuras.GetAuraDataBySlot(unitstr, tooltipSlots[i])
for gameSlot = 1, 16 do
local check = C_UnitAuras.GetDebuffDataByIndex(unitstr, gameSlot)
if check and check.name == ownAura.name and check.sourceGUID == ownAura.sourceGUID then
GameTooltip:SetUnitAura(unitstr, i, "HARMFUL")
GameTooltip:SetUnitAura(unitstr, gameSlot, "HARMFUL")
return
end
end
@@ -777,7 +761,7 @@ function pfUI.uf:UpdateConfig()
if not f.buffs[i].cd then
if cooldown_anim == 1 then
-- Animation enabled: Use Model frame with CooldownFrameTemplate
f.buffs[i].cd = CreateFrame("Model", f.buffs[i]:GetName() .. "Cooldown", f.buffs[i], "CooldownFrameTemplate")
f.buffs[i].cd = CreateFrame(COOLDOWN_FRAME_TYPE, f.buffs[i]:GetName() .. "Cooldown", f.buffs[i], "CooldownFrameTemplate")
else
-- Animation disabled: Use regular Frame with dummy functions
f.buffs[i].cd = CreateFrame("Frame", f.buffs[i]:GetName() .. "Cooldown", f.buffs[i])
@@ -850,7 +834,7 @@ function pfUI.uf:UpdateConfig()
if not f.debuffs[i].cd then
if cooldown_anim == 1 then
-- Animation enabled: Use Model frame with CooldownFrameTemplate
f.debuffs[i].cd = CreateFrame("Model", f.debuffs[i]:GetName() .. "Cooldown", f.debuffs[i], "CooldownFrameTemplate")
f.debuffs[i].cd = CreateFrame(COOLDOWN_FRAME_TYPE, f.debuffs[i]:GetName() .. "Cooldown", f.debuffs[i], "CooldownFrameTemplate")
else
-- Animation disabled: Use regular Frame with dummy functions
f.debuffs[i].cd = CreateFrame("Frame", f.debuffs[i]:GetName() .. "Cooldown", f.debuffs[i])
@@ -1651,13 +1635,11 @@ function pfUI.uf:RefreshUnit(unit, component)
-- buffs
if unit.buffs and ( component == "all" or component == "aura" ) then
-- one GetAuraSlots enumeration per refresh, then a positional read per
-- slot id: allocates nothing and never re-walks the aura array per icon
ScanAuraSlots(unitstr, "HELPFUL", auraSlots, unit.config.bufflimit)
for i=1, unit.config.bufflimit do
if not unit.buffs[i] then break end
local name, icon, count, _, duration, expirationTime, _, _, _, spellId = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
-- positional UnitBuff allocates nothing (vs a table per icon per refresh)
local name, icon, count, _, duration, expirationTime, _, _, _, spellId = C_UnitAuras.UnitBuff(unitstr, i)
if name then
unit.buffs[i].texture:SetTexture(icon)
@@ -1741,13 +1723,6 @@ function pfUI.uf:RefreshUnit(unit, component)
reposition = true
end
-- selfdebuff narrows to player-cast harmful auras via the PLAYER filter.
-- Player-frame debuffs aren't gated on it (it'd hide most party-applied
-- effects on you). One GetAuraSlots enumeration per refresh; the i-th slot
-- is the i-th aura of the filtered list, so `i` stays the tooltip index.
local filter = (unit.label ~= "player" and selfdebuff == "1") and "HARMFUL|PLAYER" or "HARMFUL"
ScanAuraSlots(unitstr, filter, auraSlots, unit.config.debufflimit)
for i=1, unit.config.debufflimit do
if not unit.debuffs[i] then break end
@@ -1764,8 +1739,12 @@ function pfUI.uf:RefreshUnit(unit, component)
invert_h * ((row+buffrow)*(multiply*default_border + unit.config.debuffsize + 1) + (multiply*default_border + 1)))
end
-- positional read by slot id allocates nothing
local name, icon, count, dispelType, duration, expirationTime = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
-- selfdebuff narrows to player-cast harmful auras via the PLAYER filter.
-- Player-frame debuffs aren't gated on it (it'd hide most party-applied
-- effects on you).
-- positional UnitDebuff allocates nothing; PLAYER predicate honored for selfdebuff
local filter = (unit.label ~= "player" and selfdebuff == "1") and "PLAYER" or nil
local name, icon, count, dispelType, duration, expirationTime = C_UnitAuras.UnitDebuff(unitstr, i, filter)
if name then
texture, stacks, dtype = icon, count, dispelType
else
@@ -1855,9 +1834,8 @@ function pfUI.uf:RefreshUnit(unit, component)
local present = pfUI.uf.dispelPresent or {}
pfUI.uf.dispelPresent = present
for k in pairs(present) do present[k] = nil end
local n = ScanAuraSlots(unitstr, "HARMFUL", auraSlots)
for i=1,n do
local name, _, _, dispelType = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
for i=1,16 do
local name, _, _, dispelType = C_UnitAuras.UnitDebuff(unitstr, i)
if name and dispelType and dispelType ~= "" then present[dispelType] = true end
end
@@ -1947,9 +1925,9 @@ function pfUI.uf:RefreshUnit(unit, component)
local pos = 1
if table.getn(unit.indicators) > 0 then
local n = ScanAuraSlots(unitstr, "HELPFUL", auraSlots)
for i=1,n do
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
local i = 1
while true do
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitBuff(unitstr, i)
if not name then break end
local texLower = string.lower(icon)
local timeleft = expirationTime > 0 and (expirationTime - GetTime()) or nil
@@ -1970,13 +1948,14 @@ function pfUI.uf:RefreshUnit(unit, component)
break
end
end
i = i + 1
end
end
if table.getn(unit.indicator_custom) > 0 then
local n = ScanAuraSlots(unitstr, "HELPFUL", auraSlots)
for i=1,n do
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
local ai = 1
while true do
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitBuff(unitstr, ai)
if not name then break end
local timeleft = expirationTime > 0 and (expirationTime - GetTime()) or nil
local lowerName = string.lower(name)
@@ -1987,12 +1966,12 @@ function pfUI.uf:RefreshUnit(unit, component)
break
end
end
ai = ai + 1
end
local debuffFilter = unit.config.selfdebuff == "1" and "HARMFUL|PLAYER" or "HARMFUL"
n = ScanAuraSlots(unitstr, debuffFilter, auraSlots)
for i=1,n do -- scan for custom debuffs
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
local debuffFilter = unit.config.selfdebuff == "1" and "PLAYER" or nil
for i=1,16 do -- scan for custom debuffs
local name, icon, count, _, _, expirationTime = C_UnitAuras.UnitDebuff(unitstr, i, debuffFilter)
if name then
local timeleft = expirationTime > 0 and (expirationTime - GetTime()) or nil
for _, filter in pairs(unit.indicator_custom) do
@@ -2254,7 +2233,7 @@ function pfUI.uf:AddIcon(frame, pos, icon, timeleft, stacks, start, duration)
-- Check if parent frame has cooldown animation enabled
local parent_cooldown_anim = frame.config and tonumber(frame.config.cooldown_anim) or 1
if parent_cooldown_anim == 1 then
frame.icon[pos].cd = CreateFrame("Model", nil, frame.icon[pos])
frame.icon[pos].cd = CreateFrame(COOLDOWN_FRAME_TYPE, nil, frame.icon[pos])
else
frame.icon[pos].cd = CreateFrame("Frame", nil, frame.icon[pos])
frame.icon[pos].cd.AdvanceTime = DoNothing
+43
View File
@@ -0,0 +1,43 @@
-- load pfUI environment
setfenv(1, pfUI:GetEnvironment())
-- [[ Constants ]]--
EVENTS_MINIMAP_ZONE_UPDATE = {"PLAYER_ENTERING_WORLD", "MINIMAP_ZONE_CHANGED"}
MICRO_BUTTONS = {
'CharacterMicroButton', 'SpellbookMicroButton', 'TalentMicroButton',
'QuestLogMicroButton', 'SocialsMicroButton', 'WorldMapMicroButton',
'MainMenuMicroButton', 'HelpMicroButton',
}
NAMEPLATE_OBJECTORDER = { "border", "glow", "name", "level", "levelicon", "raidicon" }
NAMEPLATE_FRAMETYPE = "Button"
MINIMAP_TRACKING_FRAME = _G.MiniMapTrackingFrame
FRIENDS_NAME_LOCATION = "ButtonTextNameLocation"
COOLDOWN_FRAME_TYPE = "Model"
LOOT_BUTTON_FRAME_TYPE = "LootButton"
PLAYER_BUFF_START_ID = -1
ACTIONBAR_SECURE_TEMPLATE_BAR = nil
ACTIONBAR_SECURE_TEMPLATE_BUTTON = nil
--[[ Vanilla API Extensions ]]--
do -- RunMacroText
local obj = { ["GetText"] = function(self) return self.text end }
obj = setmetatable(obj, {__index = function(tab,key)
local value = function() return end
rawset(tab,key,value)
return value
end})
function RunMacroText(text)
obj.text = text
ChatEdit_ParseText(obj, 1)
end
end
+2358
View File
File diff suppressed because it is too large Load Diff
-2377
View File
File diff suppressed because it is too large Load Diff
-2991
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,3 +1,3 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="..\env\tables_stock.lua"/>
<Include file="..\compat\vanilla.lua"/>
</Ui>
+1
View File
@@ -72,6 +72,7 @@
<Include file="..\modules\totems.lua"/>
<Include file="..\modules\macrotweak.lua"/>
<Include file="..\modules\macroicons.lua"/>
<Include file="..\modules\turtle-wow.lua"/>
<Include file="..\modules\superwow.lua"/>
<Include file="..\modules\innervatecall.lua"/>
<Include file="..\modules\nampower.lua"/>
+7 -1
View File
@@ -35,6 +35,12 @@
<Include file="..\skins\blizzard\tooltips.lua"/>
<Include file="..\skins\blizzard\tabard.lua"/>
<Include file="..\skins\blizzard\itemtext.lua"/>
<Include file="..\skins\blizzard\lft.lua"/>
<Include file="..\skins\blizzard\turtle_shop.lua"/>
<!-- Turtle WoW -->
<Include file="..\skins\blizzard\barbershop.lua"/>
<Include file="..\skins\blizzard\transmog.lua"/>
<Include file="..\skins\blizzard\ebc.lua"/>
<!-- Turtle WoW skins live in init\turtle.xml (pfUI_Turtle.toc only). -->
</Ui>
-14
View File
@@ -1,14 +0,0 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<!-- Turtle WoW only: pulled in by pfUI_Turtle.toc, which ClassicAPI selects
when it detects a Turtle client. Everything in here targets frames that
only a Turtle client ever creates. -->
<Include file="..\env\tables_turtle.lua"/>
<Include file="..\skins\blizzard\lft.lua"/>
<Include file="..\skins\blizzard\turtle_shop.lua"/>
<Include file="..\skins\blizzard\barbershop.lua"/>
<Include file="..\skins\blizzard\transmog.lua"/>
<Include file="..\skins\blizzard\ebc.lua"/>
<Include file="..\modules\turtle-wow.lua"/>
</Ui>
-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
+3 -3
View File
@@ -1016,7 +1016,7 @@ pfUI:RegisterModule("actionbar", function ()
local id = (bar-1)*12+button
local exists = _G[button_name] and true or nil
local f = _G[button_name] or CreateFrame("Button", button_name, parent)
local f = _G[button_name] or CreateFrame("Button", button_name, parent, ACTIONBAR_SECURE_TEMPLATE_BUTTON)
-- no button available, create a new one
if not exists then
@@ -1042,7 +1042,7 @@ pfUI:RegisterModule("actionbar", function ()
f.slot = id
-- cooldown
f.cd = CreateFrame("Model", f:GetName() .. "Cooldown", f, "CooldownFrameTemplate")
f.cd = CreateFrame(COOLDOWN_FRAME_TYPE, f:GetName() .. "Cooldown", f, "CooldownFrameTemplate")
f.cd.pfCooldownStyleAnimation = 1
f.cd.pfCooldownType = "NOGCD"
f.cd.pfCooldownSize = cd_size
@@ -1233,7 +1233,7 @@ pfUI:RegisterModule("actionbar", function ()
-- create frame
local init = not bars[i]
bars[i] = bars[i] or CreateFrame("Frame", "pfActionBar" .. barnames[i], UIParent)
bars[i] = bars[i] or CreateFrame("Frame", "pfActionBar" .. barnames[i], UIParent, ACTIONBAR_SECURE_TEMPLATE_BAR)
bars[i]:SetID(i)
-- autohide
+1 -1
View File
@@ -396,7 +396,7 @@ pfUI:RegisterModule("bags", function ()
if tpl == "BankItemButtonGenericTemplate" then
local bankslot = pfUI.bags[bag].slots[slot].frame
local name = "pfBag" .. bag .. "item" .. slot .. "Cooldown"
bankslot.cd = CreateFrame("Model", name, bankslot, "CooldownFrameTemplate")
bankslot.cd = CreateFrame(COOLDOWN_FRAME_TYPE, name, bankslot, "CooldownFrameTemplate")
bankslot.cd:SetAllPoints(bankslot)
bankslot.cd.pfCooldownStyleAnimation = 1
bankslot.cd.pfCooldownType = "ALL"
+1 -16
View File
@@ -7,15 +7,6 @@ pfUI:RegisterModule("buff", function ()
local br, bg, bb, ba = GetStringColor(pfUI_config.appearance.border.color)
-- Player aura slot ids, enumerated once per refresh pass (ScanPlayerAuraSlots)
-- and read per button by its aura index: one GetAuraSlots walk per range
-- instead of a by-index walk per button.
local helpfulSlots, harmfulSlots = {}, {}
local function ScanPlayerAuraSlots()
ScanAuraSlots("player", "HELPFUL", helpfulSlots, 32)
ScanAuraSlots("player", "HARMFUL", harmfulSlots, 16)
end
local function RefreshBuffButton(buff)
if buff.btype == "HELPFUL" then
if C.buffs.separateweapons == "1" then
@@ -32,8 +23,7 @@ pfUI:RegisterModule("buff", function ()
CreateBackdropShadow(buff)
end
local slots = buff.btype == "HELPFUL" and helpfulSlots or harmfulSlots
local name, icon, count, dispelType, _, expirationTime, _, _, _, spellId = C_UnitAuras.UnitAuraBySlot("player", slots[buff.id])
local name, icon, count, dispelType, _, expirationTime, _, _, _, spellId = C_UnitAuras.UnitAura("player", buff.id, buff.btype)
--detect weapon buffs
if buff.btype == "HELPFUL" and ((C.buffs.separateweapons == "0" and buff.gid <= pfUI.buff.wepbuffs.count) or (pfUI.buff.wepbuffs.count > 0 and buff.weapon ~= nil)) then
@@ -176,8 +166,6 @@ pfUI:RegisterModule("buff", function ()
pfUI.buff.wepbuffs.count = 0
end
ScanPlayerAuraSlots()
for i=1,32 do
RefreshBuffButton(pfUI.buff.buffs.buttons[i])
end
@@ -258,9 +246,6 @@ pfUI:RegisterModule("buff", function ()
end
end)
-- CreateBuffButton refreshes each new button from the slot buffers
ScanPlayerAuraSlots()
-- Weapon Buffs
pfUI.buff.wepbuffs = CreateFrame("Frame", "pfWepBuffFrame", UIParent)
pfUI.buff.wepbuffs.count = 0
+10 -28
View File
@@ -73,16 +73,9 @@ pfUI:RegisterModule("buffwatch", function ()
return anchor
end
-- reusable GetAuraSlots buffer, filled once per RefreshBuffBarFrame
local auraSlots = {}
-- Separate buffer for the tooltip handler: OnEnter can fire while a refresh
-- is showing/hiding bars under the cursor, so it must not share the above.
local tooltipSlots = {}
-- Reads one aura by the slot id GetAuraSlots returned (nil slot -> nil).
local function GetBuffData(unit, slot)
local name, icon, count, dispelType, _, expirationTime = C_UnitAuras.UnitAuraBySlot(unit, slot)
local function GetBuffData(unit, id, type, selfdebuff)
local filter = (selfdebuff and type == "HARMFUL") and "HARMFUL|PLAYER" or type
local name, icon, count, dispelType, _, expirationTime = C_UnitAuras.UnitAura(unit, id, filter)
if not name then return end
local remaining = expirationTime > 0 and (expirationTime - GetTime()) or 0
return remaining, icon, name, count, dispelType
@@ -120,22 +113,17 @@ pfUI:RegisterModule("buffwatch", function ()
GameTooltip:SetUnitAura("player", this.id, this.type)
elseif this.type == "HARMFUL" then
-- selfdebuff filters the displayed list to player-cast harmful auras, but
-- SetUnitAura's index has to be into the unfiltered HARMFUL list. Look up
-- the displayed aura via the PLAYER filter, then find its position in the
-- unfiltered list by name + sourceGUID.
--
-- The unfiltered list is NOT capped at 16: once a unit's 16 debuff slots
-- are full the server parks further debuffs in buff slots, and
-- C_UnitAuras reports those as harmful too. So enumerate what it has.
-- SetUnitAura's index has to be into the engine's full HARMFUL list. Look
-- up the displayed aura via the PLAYER filter, then scan engine slots for
-- one whose name + sourceGUID match.
local config = this.parent and this.parent.config
if config and config.selfdebuff == "1" then
local ownAura = C_UnitAuras.GetAuraDataByIndex(this.unit, this.id, "HARMFUL|PLAYER")
if ownAura then
local n = ScanAuraSlots(this.unit, "HARMFUL", tooltipSlots)
for i = 1, n do
local check = C_UnitAuras.GetAuraDataBySlot(this.unit, tooltipSlots[i])
for gameSlot = 1, 16 do
local check = C_UnitAuras.GetDebuffDataByIndex(this.unit, gameSlot)
if check and check.name == ownAura.name and check.sourceGUID == ownAura.sourceGUID then
GameTooltip:SetUnitAura(this.unit, i, "HARMFUL")
GameTooltip:SetUnitAura(this.unit, gameSlot, "HARMFUL")
break
end
end
@@ -246,15 +234,9 @@ pfUI:RegisterModule("buffwatch", function ()
local function RefreshBuffBarFrame(frame)
-- reinitialize all active buffs
local selfdebuff = frame.config.selfdebuff == "1"
local filter = (selfdebuff and frame.type == "HARMFUL") and "HARMFUL|PLAYER" or frame.type
-- one GetAuraSlots enumeration per refresh instead of a by-index walk per
-- bar; the i-th slot is the i-th aura of the filtered list, so `i` stays
-- the index the tooltip / cancel handlers pass to the by-index API
ScanAuraSlots(frame.unit, filter, auraSlots, 32)
for i=1,32 do
local timeleft, texture, name, stacks, dtype = GetBuffData(frame.unit, auraSlots[i])
local timeleft, texture, name, stacks, dtype = GetBuffData(frame.unit, i, frame.type, selfdebuff)
timeleft = timeleft or 0
if texture and name and name ~= "" and BuffIsVisible(frame.config, name) then
+23 -97
View File
@@ -63,23 +63,6 @@ pfUI:RegisterModule("chat", function ()
return pfUI_cache["chathistory"][realm][player][id]
end
-- [ Chat Panel Colors ]
-- The panels normally inherit pfUI's global appearance theme; custom colors let chat
-- deviate from it. CreateBackdrop is re-run first to restore the theme, so toggling
-- custom colors back off doesn't leave the previous override behind.
local function ApplyPanelColors(panel)
if not panel then return end
CreateBackdrop(panel, default_border, nil, .8)
if C.chat.global.custombg ~= "1" then return end
local r, g, b, a = GetStringColor(C.chat.global.background)
panel.backdrop:SetBackdropColor(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
local r, g, b, a = GetStringColor(C.chat.global.border)
panel.backdrop:SetBackdropBorderColor(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
end
pfUI.chat = CreateFrame("Frame",nil,UIParent)
pfUI.chat.left = CreateFrame("Frame", "pfChatLeft", UIParent)
@@ -93,11 +76,19 @@ pfUI:RegisterModule("chat", function ()
pfUI.chat.left:SetPoint("BOTTOMLEFT", 2*default_border,2*default_border)
pfUI.chat.left:SetScript("OnShow", function() pfUI.chat:RefreshChat() end)
UpdateMovable(pfUI.chat.left)
ApplyPanelColors(pfUI.chat.left)
CreateBackdrop(pfUI.chat.left, default_border, nil, .8)
if C.chat.global.frameshadow == "1" then
CreateBackdropShadow(pfUI.chat.left)
end
if C.chat.global.custombg == "1" then
local r, g, b, a = GetStringColor(C.chat.global.background)
pfUI.chat.left.backdrop:SetBackdropColor(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
local r, g, b, a = GetStringColor(C.chat.global.border)
pfUI.chat.left.backdrop:SetBackdropBorderColor(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
end
pfUI.chat.left.panelTop = CreateFrame("Frame", "leftChatPanelTop", pfUI.chat.left)
pfUI.chat.left.panelTop:ClearAllPoints()
pfUI.chat.left.panelTop:SetHeight(C.global.font_size+default_border*2)
@@ -260,11 +251,19 @@ pfUI:RegisterModule("chat", function ()
pfUI.chat.right:SetPoint("BOTTOMRIGHT", -2*default_border,2*default_border)
pfUI.chat.right:SetScript("OnShow", function() pfUI.chat:RefreshChat() end)
UpdateMovable(pfUI.chat.right)
ApplyPanelColors(pfUI.chat.right)
CreateBackdrop(pfUI.chat.right, default_border, nil, .8)
if C.chat.global.frameshadow == "1" then
CreateBackdropShadow(pfUI.chat.right)
end
if C.chat.global.custombg == "1" then
local r, g, b, a = GetStringColor(C.chat.global.background)
pfUI.chat.right.backdrop:SetBackdropColor(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
local r, g, b, a = GetStringColor(C.chat.global.border)
pfUI.chat.right.backdrop:SetBackdropBorderColor(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
end
pfUI.chat.right.panelTop = CreateFrame("Frame", "rightChatPanelTop", pfUI.chat.right)
pfUI.chat.right.panelTop:ClearAllPoints()
pfUI.chat.right.panelTop:SetHeight(C.global.font_size+default_border*2)
@@ -297,68 +296,6 @@ pfUI:RegisterModule("chat", function ()
end
end
-- [ Chat Background Alpha ]
-- Blizzard's per-window transparency slider drives FCF_SetWindowAlpha, which only
-- touches the ChatFrame*Background textures that pfUI hides on docked frames. Mirror
-- the window's stored alpha onto the visible pfUI backdrop so the native slider
-- controls it directly.
local function ApplyChatBackgroundAlpha(panel, frame)
if not (panel and panel.backdrop and frame) then return end
local _, _, _, _, _, alpha = GetChatWindowInfo(frame:GetID())
alpha = tonumber(alpha)
if not alpha then return end
local r, g, b = panel.backdrop:GetBackdropColor()
panel.backdrop:SetBackdropColor(r, g, b, alpha)
end
function pfUI.chat:RefreshBackgroundAlpha()
-- Custom colors own the alpha. C.chat.global.background carries its own alpha, is
-- set by profiles and is shared with the meter skins, so the native slider must not
-- overwrite it -- doing so reverted the configured opacity on every refresh. The
-- slider only drives the panel when the user hasn't opted into pfUI's chat colors.
if C.chat.global.custombg == "1" then return end
-- left panel follows the currently selected docked tab
local selected = SELECTED_CHAT_FRAME
if not (selected and selected:GetParent() == pfUI.chat.left) then
selected = ChatFrame1
end
ApplyChatBackgroundAlpha(pfUI.chat.left, selected)
if C.chat.right.enable == "1" then
ApplyChatBackgroundAlpha(pfUI.chat.right, ChatFrame3)
end
end
-- live config apply, resolved by the gui as U["chat"]. Lets the color pickers
-- take effect on the spot instead of waiting for a /reload.
function pfUI.chat:UpdateConfig()
ApplyPanelColors(pfUI.chat.left)
ApplyPanelColors(pfUI.chat.right)
pfUI.chat:RefreshBackgroundAlpha()
end
function pfUI.chat:MigrateBackgroundAlpha()
-- Runs once per character. The previous SetupPositions default stored a hard 0 window
-- alpha, which now renders the pfUI backdrop fully transparent. Restore the historical
-- 0.8 look for any pfUI-managed window still sitting at 0. Only existing installs that
-- already ran chat setup carry that legacy 0; fresh installs get 0.8 from SetupPositions.
if pfUI_init.chatbgalpha then return end
if not pfUI_init["chat_position"] then return end
pfUI_init.chatbgalpha = true
local frames = { ChatFrame1, ChatFrame2 }
if C.chat.right.enable == "1" then table.insert(frames, ChatFrame3) end
for _, frame in ipairs(frames) do
local _, _, _, _, _, alpha = GetChatWindowInfo(frame:GetID())
alpha = tonumber(alpha)
if alpha and alpha <= 0 then
FCF_SetWindowAlpha(frame, 0.8)
end
end
end
function pfUI.chat:RefreshChat()
local panelheight = C.global.font_size*1.5 + default_border*2 + 2
@@ -510,13 +447,9 @@ pfUI:RegisterModule("chat", function ()
for index, value in pairs(DOCKED_CHAT_FRAMES) do
FCF_UpdateButtonSide(value)
end
pfUI.chat:RefreshBackgroundAlpha()
end
hooksecurefunc("FCF_SaveDock", pfUI.chat.RefreshChat)
hooksecurefunc("FCF_SetWindowAlpha", function() pfUI.chat:RefreshBackgroundAlpha() end)
hooksecurefunc("FCF_SelectDockFrame", function() pfUI.chat:RefreshBackgroundAlpha() end)
if C.chat.global.tabmouse == "1" then
pfUI.chat.mouseovertab = CreateFrame("Frame")
@@ -567,7 +500,7 @@ pfUI:RegisterModule("chat", function ()
FCF_SetLocked(ChatFrame1, 1)
FCF_SetWindowName(ChatFrame1, GENERAL)
FCF_SetWindowColor(ChatFrame1, 0, 0, 0)
FCF_SetWindowAlpha(ChatFrame1, 0.8)
FCF_SetWindowAlpha(ChatFrame1, 0)
FCF_SetChatWindowFontSize(ChatFrame1, 12)
ChatFrame1:SetUserPlaced(1)
@@ -575,7 +508,7 @@ pfUI:RegisterModule("chat", function ()
FCF_SetLocked(ChatFrame2, 1)
FCF_SetWindowName(ChatFrame2, COMBAT_LOG)
FCF_SetWindowColor(ChatFrame2, 0, 0, 0)
FCF_SetWindowAlpha(ChatFrame2, 0.8)
FCF_SetWindowAlpha(ChatFrame2, 0)
FCF_SetChatWindowFontSize(ChatFrame2, 12)
ChatFrame2:SetUserPlaced(1)
@@ -585,7 +518,7 @@ pfUI:RegisterModule("chat", function ()
FCF_SetLocked(ChatFrame3, 1)
FCF_SetWindowName(ChatFrame3, T["Loot & Spam"])
FCF_SetWindowColor(ChatFrame3, 0, 0, 0)
FCF_SetWindowAlpha(ChatFrame3, 0.8)
FCF_SetWindowAlpha(ChatFrame3, 0)
FCF_SetChatWindowFontSize(ChatFrame3, 12)
FCF_UnDockFrame(ChatFrame3)
FCF_SetTabPosition(ChatFrame3, 0)
@@ -633,9 +566,6 @@ pfUI:RegisterModule("chat", function ()
end
pfUI.chat:SetScript("OnEvent", function()
-- restore legacy chat windows stuck at 0 alpha before anything reads it
pfUI.chat:MigrateBackgroundAlpha()
-- set the default chat
FCF_SelectDockFrame(SELECTED_CHAT_FRAME)
@@ -827,7 +757,7 @@ pfUI:RegisterModule("chat", function ()
local real, _ = strsplit(":", name)
local color = unknowncolorhex
local match = false
local _, class, _, raceKey, sex = C_PlayerCache.GetPlayerInfoByName(real)
local _, class = C_PlayerCache.GetPlayerInfoByName(real)
-- local guid = GetCurrentChatGUID()
-- if guid then
-- _, class = GetPlayerInfoByGUID(guid)
@@ -845,12 +775,8 @@ pfUI:RegisterModule("chat", function ()
end
if C.chat.text.tintunknown == "1" or match then
local icon = ""
if match and C.chat.text.playericons == "1" then
icon = GetFactionIcon(raceKey) .. GetRaceIcon(raceKey, sex)
end
text = string.gsub(text, "|Hplayer:"..name.."|h%["..real.."%]|h(.-:-)",
left..icon..color.."|Hplayer:"..name.."|h" .. color .. real .. "|h|r"..right.."%1")
left..color.."|Hplayer:"..name.."|h" .. color .. real .. "|h|r"..right.."%1")
end
end
end
+3 -4
View File
@@ -2867,7 +2867,6 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(nil, T["Generate Playerlinks"], C.chat.text, "playerlinks", "checkbox")
CreateConfig(nil, T["Enable URL Detection"], C.chat.text, "detecturl", "checkbox")
CreateConfig(nil, T["Enable Class Colors"], C.chat.text, "classcolor", "checkbox")
CreateConfig(nil, T["Show Faction & Race Icons"] .. " " .. GetPlayerRaceIcons(), C.chat.text, "playericons", "checkbox")
CreateConfig(nil, T["Enable Player Levels"], C.chat.text, "playerlevel", "checkbox")
CreateConfig(nil, T["Who Search Unknown Classes (|cffffaaaaExperimental|r)"], C.chat.text, "whosearchunknown", "checkbox")
CreateConfig(nil, T["Colorize Unknown Classes"], C.chat.text, "tintunknown", "checkbox")
@@ -2881,9 +2880,9 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(nil, T["Only Show Chat Dock On Mouseover"], C.chat.global, "tabmouse", "checkbox")
CreateConfig(nil, T["Enable Chat Tab Flashing"], C.chat.global, "chatflash", "checkbox")
CreateConfig(nil, T["Enable Frame Shadow"], C.chat.global, "frameshadow", "checkbox")
CreateConfig(U["chat"], T["Enable Custom Colors"], C.chat.global, "custombg", "checkbox")
CreateConfig(U["chat"], T["Chat Background Color"], C.chat.global, "background", "color")
CreateConfig(U["chat"], T["Chat Border Color"], C.chat.global, "border", "color")
CreateConfig(nil, T["Enable Custom Colors"], C.chat.global, "custombg", "checkbox")
CreateConfig(nil, T["Chat Background Color"], C.chat.global, "background", "color")
CreateConfig(nil, T["Chat Border Color"], C.chat.global, "border", "color")
CreateConfig(nil, T["Enable Custom Incoming Whispers Layout"], C.chat.global, "whispermod", "checkbox")
CreateConfig(nil, T["Incoming Whispers Color"], C.chat.global, "whisper", "color")
CreateConfig(nil, T["Enable Sticky Chat"], C.chat.global, "sticky", "checkbox")
+1 -1
View File
@@ -511,7 +511,7 @@ pfUI:RegisterModule("loot", function ()
end
function pfUI.loot:CreateSlot(id)
local frame = CreateFrame("LootButton", 'pfLootButton'..id, pfUI.loot)
local frame = CreateFrame(LOOT_BUTTON_FRAME_TYPE, 'pfLootButton'..id, pfUI.loot)
frame:RegisterForClicks('LeftButtonUp', 'RightButtonUp')
frame:SetPoint("LEFT", border*2, 0)
frame:SetPoint("RIGHT", -border*2, 0)
+44 -45
View File
@@ -116,7 +116,6 @@ pfUI:RegisterModule("nameplates", function ()
-- Reusable per-plate debuff display buffer (avoid GC churn from per-call table creation)
local debuffDisplayBuf = {} -- [i] = { effect, texture, stacks, dtype, duration, timeleft }
for i = 1, 16 do debuffDisplayBuf[i] = {} end
local auraSlots = {} -- reusable GetAuraSlots buffer for the per-plate aura scan
local threatMemory = {} -- guid -> true if mob had player targeted
-- local debuffSeen = {} -- reusable table for debuff tracking (avoid GC churn)
@@ -297,23 +296,18 @@ pfUI:RegisterModule("nameplates", function ()
return plate.creatureType
end
-- Totem icon: UnitCreatedBySpell returns the totem-drop spell, whose icon IS
-- the totem's icon. It's a broadcast descriptor field the client has for every
-- summoned unit in range, so it resolves immediately for passive and active
-- totems alike -- no self-aura read or attack-cast capture needed.
--
-- Re-read the spell every call rather than caching the icon outright: a shaman
-- can swap the totem in place (same unit, new drop spell) with no plate re-add
-- to invalidate a cache, so key the cached texture on the spell id and refresh
-- it only when the spell changes.
-- Totem icon, read straight from the game:
-- * Passive totems self-cast their provided buff, so they carry exactly one
-- aura whose icon IS the totem's icon (Totem::Summon TOTEM_PASSIVE).
-- * Active totems (Searing/Magma/Fire Nova) cast at enemies and hold no
-- self-aura, so their icon arrives via UNIT_SPELLCAST_SUCCEEDED (cached
-- into plate.totemIcon by the event handler); nil here until then.
local function TotemPlate(plate)
if C.nameplates.totemicons ~= "1" then return nil end
if CreatureType(plate) ~= 11 then return nil end
local spellId = UnitCreatedBySpell(plate.cachedGuid)
if spellId ~= plate.totemSpell then
plate.totemSpell = spellId
plate.totemIcon = spellId and C_Spell.GetSpellTexture(spellId) or nil
end
if plate.totemIcon then return plate.totemIcon end
local aura = C_UnitAuras.GetBuffDataByIndex(plate.cachedGuid, 1)
if aura then plate.totemIcon = aura.icon end
return plate.totemIcon
end
@@ -433,7 +427,7 @@ pfUI:RegisterModule("nameplates", function ()
plate.debuffs[index].cd.SetSequenceTime = DoNothing
else
-- Use CooldownFrameTemplate for animation
plate.debuffs[index].cd = CreateFrame("Model", plate.platename.."Debuff"..index.."Cooldown", plate.debuffs[index], "CooldownFrameTemplate")
plate.debuffs[index].cd = CreateFrame(COOLDOWN_FRAME_TYPE, plate.platename.."Debuff"..index.."Cooldown", plate.debuffs[index], "CooldownFrameTemplate")
plate.debuffs[index].cd:SetAllPoints(plate.debuffs[index])
plate.debuffs[index].cd:SetFrameLevel(6)
end
@@ -505,6 +499,7 @@ nameplates:RegisterEvent("UNIT_SPELLCAST_START")
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
nameplates:RegisterEvent("UNIT_SPELLCAST_STOP")
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
nameplates:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
nameplates:SetScript("OnEvent", function()
@@ -593,7 +588,6 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
plate.nameplate.unit = arg1
plate.nameplate.creatureType = nil -- recompute for the new unit
plate.nameplate.totemIcon = nil
plate.nameplate.totemSpell = nil
if guid then
plateByGuid[guid] = plate.nameplate
-- Seed: the unit may already be mid-cast (its UNIT_SPELLCAST_START
@@ -671,6 +665,22 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
end
end
elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
-- Active totems (Searing/Magma/Fire Nova) carry no self-aura, so their
-- attack cast is the only icon source. Capture it once per totem, gated on
-- creature type so a normal caster's spell never styles it as a totem.
if arg1 and strfind(arg1, "^nameplate") then
local guid = UnitGUID(arg1)
local plate = guid and plateByGuid[guid]
if plate and not plate.totemIcon and arg3 and CreatureType(plate) == 11 then
local tex = C_Spell.GetSpellTexture(arg3)
if tex then
plate.totemIcon = tex
plate.castUpdate = true -- re-render now so the icon shows
end
end
end
elseif event == "UNIT_AURA" then
-- ClassicAPI: fires with arg1 == "nameplateN" when a unit's aura set
-- changes (add/remove/modify). Flag the matching plate so OnUpdate does a
@@ -771,8 +781,6 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
DisableObject(nameplate.original.healthbar)
DisableObject(nameplate.original.castbar)
local NAMEPLATE_OBJECTORDER = { "border", "glow", "name", "level", "levelicon", "raidicon" }
for i, object in pairs({parent:GetRegions()}) do
if NAMEPLATE_OBJECTORDER[i] and NAMEPLATE_OBJECTORDER[i] == "raidicon" then
nameplate[NAMEPLATE_OBJECTORDER[i]] = object
@@ -1031,29 +1039,13 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
local mouseover = plate.cachedGuid and plate.cachedGuid == frameState.mouseoverGuid or nil
local unitstr = target and "target" or mouseover and "mouseover" or plate.cachedGuid or nil
-- target event sometimes fires too quickly, where nameplate identifiers are not
-- yet updated. So while being inside this event, we cannot trust the unitstr.
if event == "PLAYER_TARGET_CHANGED" then unitstr = nil end
-- remove unitstr when it doesn't resolve to this plate's unit (stale istarget,
-- stale mouseover guid or a despawned unit). Must run before the cache fills
-- below -- an unrelated unitstr would poison cache.player/minion with the
-- *other* unit's answer, and the nil-gate would then never recompute it.
if unitstr and UnitName(unitstr) ~= name then unitstr = nil end
-- resolve player vs npc from plate's own unit so libunitscan can't return
-- a player record for an NPC sharing the same name (e.g. Chromie). Stored
-- as true/false/nil so it doubles as the GetUnitInfo hint.
if plate.cache.player == nil and unitstr then
plate.cache.player = UnitIsPlayer(unitstr) and true or false
end
if plate.cache.minion == nil and unitstr then
plate.cache.minion = UnitIsMinion(unitstr) and true or false
end
local class, ulevel, elite, player, guild
if not plate.cache.minion then
class, ulevel, elite, player, guild = GetUnitInfo(name, true, plate.cache.player)
end
local class, ulevel, elite, player, guild = GetUnitInfo(name, true, plate.cache.player)
if plate.cache.player ~= nil then player = plate.cache.player or nil end
-- Use database level ONLY if current level is ?? (fixes ?? after reload, but doesn't override visible levels)
@@ -1073,11 +1065,18 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
if player and unittype == "ENEMY_NPC" then unittype = "ENEMY_PLAYER" end
if player and unittype == "FRIENDLY_NPC" then unittype = "FRIENDLY_PLAYER" end
elite = plate.original.levelicon:IsShown() and not player and "boss" or elite
if not class and not plate.cache.minion then plate.wait_for_scan = true end
if not class then plate.wait_for_scan = true end
-- skip data updates on invisible frames
if not visible then return end
-- target event sometimes fires too quickly, where nameplate identifiers are not
-- yet updated. So while being inside this event, we cannot trust the unitstr.
if event == "PLAYER_TARGET_CHANGED" then unitstr = nil end
-- remove unitstr on unit name mismatch
if unitstr and UnitName(unitstr) ~= name then unitstr = nil end
-- always make sure to keep plate visible
plate:Show()
@@ -1111,7 +1110,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
local TotemIcon = TotemPlate(plate)
if TotemIcon then
-- icon resolved from the totem-drop spell (already a full path)
-- icon resolved from the totem's aura / attack cast (already a full path)
plate.totem.icon:SetTexture(TotemIcon)
plate.glow:Hide()
@@ -1315,12 +1314,11 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
if unitstr then
local filter = cfg.owndebuffs and "HARMFUL|PLAYER" or "HARMFUL"
local now = GetTime()
-- one GetAuraSlots enumeration, then positional by-slot reads straight
-- into the reusable buffer: the per-plate scan allocates nothing (no
-- per-aura table, no result array) and walks the aura array once
local n = ScanAuraSlots(unitstr, filter, auraSlots, 16)
for i = 1, n do
local aname, icon, count, dispelType, duration, expirationTime = C_UnitAuras.UnitAuraBySlot(unitstr, auraSlots[i])
-- positional UnitAura writes straight into the reusable buffer, so the
-- per-plate scan allocates nothing (no per-aura table, no result array)
local i = 1
while debuffCount < 16 do
local aname, icon, count, dispelType, duration, expirationTime = C_UnitAuras.UnitAura(unitstr, i, filter)
if not aname then break end
debuffCount = debuffCount + 1
local b = debuffDisplayBuf[debuffCount]
@@ -1330,6 +1328,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
b.dtype = dispelType
b.duration = duration
b.timeleft = (expirationTime and expirationTime > 0) and (expirationTime - now) or nil
i = i + 1
end
end
for i = 1, 16 do
@@ -1552,7 +1551,7 @@ nameplates:RegisterEvent("PLAYER_GUILD_UPDATE")
-- otherwise an NPC sharing a name with a known player flips wait_for_scan
-- off here, then OnDataChanged re-sets it, every frame until the mob scan
-- lands.
if nameplate.wait_for_scan and not nameplate.cache.minion and GetUnitInfo(name, true, nameplate.cache.player) then
if nameplate.wait_for_scan and GetUnitInfo(name, true, nameplate.cache.player) then
nameplate.wait_for_scan = nil
update = true
end
+4 -10
View File
@@ -457,7 +457,7 @@ pfUI:RegisterModule("panel", function()
do -- Zone
local widget = CreateFrame("Frame", "pfPanelWidgetZone", UIParent)
for _,event in pairs({"PLAYER_ENTERING_WORLD", "MINIMAP_ZONE_CHANGED"}) do
for _,event in pairs(EVENTS_MINIMAP_ZONE_UPDATE) do
widget:RegisterEvent(event)
end
widget.Tooltip = function()
@@ -777,15 +777,9 @@ pfUI:RegisterModule("panel", function()
pfUI.panel.microbutton:SetSize(145, 23)
pfUI.panel.microbutton:SetFrameStrata("MEDIUM")
local microButtons = {
'CharacterMicroButton', 'SpellbookMicroButton', 'TalentMicroButton',
'QuestLogMicroButton', 'SocialsMicroButton', 'WorldMapMicroButton',
'MainMenuMicroButton', 'HelpMicroButton',
}
for i=1,table.getn(microButtons) do
local anchor = _G[microButtons[i-1]] or pfUI.panel.microbutton
local button = _G[microButtons[i]]
for i=1,table.getn(MICRO_BUTTONS) do
local anchor = _G[MICRO_BUTTONS[i-1]] or pfUI.panel.microbutton
local button = _G[MICRO_BUTTONS[i]]
button:ClearAllPoints()
button:SetParent(pfUI.panel.microbutton)
if i == 1 then
+1 -1
View File
@@ -81,7 +81,7 @@ pfUI:RegisterModule("socialmod", function ()
if not info or not info.name or info.name == _G.UNKNOWN then break end
local name = info.name
local friendName = _G["FriendsFrameFriendButton"..i.."ButtonTextName"]
local friendLoc = _G["FriendsFrameFriendButton"..i.."ButtonTextNameLocation"]
local friendLoc = _G["FriendsFrameFriendButton"..i..FRIENDS_NAME_LOCATION]
local friendInfo = _G["FriendsFrameFriendButton"..i.."ButtonTextInfo"]
local caption = friendName or friendLoc
+7 -11
View File
@@ -189,7 +189,6 @@ pfUI:RegisterModule("tooltip", function ()
-- Icons come from a ClassicAPI object pool: ReleaseAll hides the whole
-- set each refresh, then we Acquire and re-anchor left-to-right.
local BUFF_SIZE, BUFF_SPACING, BUFF_MAX = 20, 2, 32
local auraSlots = {} -- reusable GetAuraSlots buffer for UpdateBuffs
pfUI.tooltip.buffs = CreateFrame("Frame", "pfTooltipBuffs", GameTooltip)
pfUI.tooltip.buffs:SetPoint("BOTTOMLEFT", GameTooltipStatusBar, "TOPLEFT", 0, default_border + 2)
pfUI.tooltip.buffs:SetHeight(BUFF_SIZE)
@@ -240,20 +239,17 @@ pfUI:RegisterModule("tooltip", function ()
end
local prev, count = nil, 0
-- one GetAuraSlots enumeration + positional by-slot reads: no per-aura
-- table and no per-index re-walk of the aura array
local n = ScanAuraSlots(unit, "HELPFUL", auraSlots, BUFF_MAX)
for i = 1, n do
local name, texture, applications, _, _, expirationTime = C_UnitAuras.UnitAuraBySlot(unit, auraSlots[i])
if not name then break end
for i = 1, BUFF_MAX do
local aura = C_UnitAuras.GetBuffDataByIndex(unit, i)
if not aura then break end
count = count + 1
local icon = pfUI.tooltip.buffpool:Acquire()
icon.texture:SetTexture(texture)
icon.stacks:SetText(applications and applications > 1 and applications or "")
icon.texture:SetTexture(aura.icon)
icon.stacks:SetText(aura.applications and aura.applications > 1 and aura.applications or "")
icon.expirationTime = expirationTime
local timeleft = expirationTime and expirationTime > 0 and (expirationTime - GetTime()) or 0
icon.expirationTime = aura.expirationTime
local timeleft = aura.expirationTime and aura.expirationTime > 0 and (aura.expirationTime - GetTime()) or 0
icon.timer:SetText(timeleft > 0 and GetColoredTimeString(timeleft) or "")
if prev then
+1 -1
View File
@@ -113,7 +113,7 @@ pfUI:RegisterModule("totems", function ()
self.bar[i].cdbg = self.bar[i].cdbg or CreateFrame("Frame", nil, self.bar[i])
self.bar[i].cdbg:SetSize(self.iconsize - 3, self.iconsize - 3)
self.bar[i].cdbg:SetPoint("CENTER", self.bar[i], "CENTER", 0, 0)
self.bar[i].cd = self.bar[i].cd or CreateFrame("Model", "pfTotemsBar"..i.."Cooldown", self.bar[i].cdbg, "CooldownFrameTemplate")
self.bar[i].cd = self.bar[i].cd or CreateFrame(COOLDOWN_FRAME_TYPE, "pfTotemsBar"..i.."Cooldown", self.bar[i].cdbg, "CooldownFrameTemplate")
self.bar[i].cd.pfCooldownStyleAnimation = 1
self.bar[i].cd.pfCooldownType = "ALL"
+92 -25
View File
@@ -1,17 +1,58 @@
pfUI:RegisterModule("tracking", function ()
_G.MiniMapTrackingFrame:UnregisterAllEvents()
_G.MiniMapTrackingFrame:Hide()
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
})
+2958 -1
View File
File diff suppressed because it is too large Load Diff
+103 -38
View File
@@ -3,8 +3,6 @@ function SlashCmdList.RELOAD(msg, editbox)
ReloadUI()
end
local addonName = ...
SLASH_PFUI1 = '/pfui'
function SlashCmdList.PFUI(msg, editbox)
pfUI.gui:SetShown(not pfUI.gui:IsShown())
@@ -15,19 +13,87 @@ function SlashCmdList.GM(msg, editbox)
ToggleHelpFrame(1)
end
local pfUI = CreateFrame("Frame", addonName, UIParent)
pfUI = CreateFrame("Frame", nil, UIParent)
pfUI:RegisterEvent("ADDON_LOADED")
-- setup bootvar
pfUI.bootup = true
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 {}
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 = 12100 -- (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"
local function FormatVersion(packed)
local x = math.floor(packed / 10000)
local y = math.floor(math.mod(packed, 10000) / 100)
local z = math.mod(packed, 100)
return string.format("v%d.%d.%d", x, y, z)
end
if not CLASSIC_API_VERSION or CLASSIC_API_VERSION < PFUI_CLASSIC_API_MIN then
local minVersion = FormatVersion(PFUI_CLASSIC_API_MIN)
pfUI.disabled = true
local detail
if not CLASSIC_API_VERSION then
detail = "The ClassicAPI DLL isn't loaded. The |cff33ffcc!!!ClassicAPI|r addon ships bundled with it -- delete your |cff33ffcc!!!ClassicAPI|r folder and install the latest release from:"
else
detail = "ClassicAPI " .. minVersion .. " or newer is required. Delete your |cff33ffcc!!!ClassicAPI|r folder and reinstall the latest release from:"
end
local function ShowRequiredPopup()
StaticPopupDialogs["PFUI_CLASSICAPI_REQUIRED"] = {
text = "|cff33ffccpf|cffffffffUI|r has been disabled.\n\n" .. detail,
button1 = OKAY,
hasEditBox = 1,
editBoxWidth = 280,
timeout = 0,
whileDead = 1,
hideOnEscape = 1,
preferredIndex = 3,
OnShow = function()
local editBox = getglobal(this:GetName().."EditBox")
if editBox then
editBox:SetText(PFUI_CLASSIC_API_LATEST_URL)
editBox:HighlightText()
editBox:SetFocus()
end
end,
}
StaticPopup_Show("PFUI_CLASSICAPI_REQUIRED")
DEFAULT_CHAT_FRAME:AddMessage(
"|cff33ffccpf|cffffffffUI|r disabled: " .. detail .. " " .. PFUI_CLASSIC_API_LATEST_URL,
1, 0.3, 0.3
)
end
local loginFrame = CreateFrame("Frame")
loginFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
loginFrame:SetScript("OnEvent", function()
loginFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
ShowRequiredPopup()
end)
elseif CLASSIC_API_VERSION < PFUI_CLASSIC_API_LATEST then
EventUtil.ContinueOnPlayerLogin(function()
C_Timer.After(8, function()
DEFAULT_CHAT_FRAME:AddMessage(
"|cff33ffccpf|rUI: ClassicAPI " .. FormatVersion(PFUI_CLASSIC_API_LATEST) .. " is available — " .. PFUI_CLASSIC_API_LATEST_URL,
1, 0.85, 0.3
)
end)
end)
end
end
-- initialize saved variables
pfUI_playerDB = {}
pfUI_config = {}
pfUI_init = {}
pfUI_profiles = {}
pfUI_addon_profiles = {}
pfUI_cache = {}
pfUI_throttle = {}
-- localization
pfUI_locale = {}
@@ -52,24 +118,35 @@ pfUI.env = {}
-- the flag; one that lacks it should drop the flag and get the safe fallback.
pfUI.handlesHookScript = true
pfUI.events = Mixin({}, CallbackRegistryMixin)
pfUI.events:OnLoad()
pfUI.events:SetUndefinedEventsAllowed(true)
if not pfUI.disabled then
pfUI.events = Mixin({}, CallbackRegistryMixin)
pfUI.events:OnLoad()
pfUI.events:SetUndefinedEventsAllowed(true)
end
-- check if macro addons are loaded (disables macrotweak/macroscan)
function pfUI:MacroAddonsLoaded()
return IsAddOnLoaded("Supermacro") or IsAddOnLoaded("SuperCleveRoidMacros") or IsAddOnLoaded("UltimaMacros")
end
pfUI.name = addonName
pfUI.path = "Interface\\AddOns\\" .. addonName
-- detect current addon path
local tocs = { "", "-master", "-tbc", "-wotlk" }
for _, name in pairs(tocs) do
local current = string.format("pfUI%s", name)
local title = C_AddOns.GetAddOnName(current)
if title then
pfUI.name = current
pfUI.path = "Interface\\AddOns\\" .. current
break
end
end
-- handle/convert media dir paths
pfUI.media = setmetatable({}, { __index = function(tab,key)
local value = tostring(key)
if value:find("img:") then
if strfind(value, "img:") then
value = string.gsub(value, "img:", pfUI.path .. "\\img\\")
elseif value:find("font:") then
elseif strfind(value, "font:") then
value = string.gsub(value, "font:", pfUI.path .. "\\fonts\\")
else
value = string.gsub(value, "Interface\\AddOns\\pfUI\\", pfUI.path .. "\\")
@@ -78,7 +155,9 @@ pfUI.media = setmetatable({}, { __index = function(tab,key)
return value
end})
pfUI.client = INTERFACE_VERSION
-- cache client version
local _, _, _, client = GetBuildInfo()
pfUI.client = client or 11200
-- setup pfUI namespace
setmetatable(pfUI.env, {__index = getfenv(0)})
@@ -312,13 +391,14 @@ function pfUI:CheckNewModules()
end
local function BackwardsCompatRegister(func, arg3)
if arg3 and type(func) == "string" and type(arg3) == "function" and func:find("vanilla") then
if arg3 and type(func) == "string" and type(arg3) == "function" and string.find(func, "vanilla") then
return arg3
end
return func
end
function pfUI:RegisterModule(name, func, arg3)
if pfUI.disabled then return end
if pfUI.module[name] then return end
func = BackwardsCompatRegister(func, arg3)
pfUI.module[name] = func
@@ -329,6 +409,7 @@ function pfUI:RegisterModule(name, func, arg3)
end
function pfUI:RegisterSkin(name, func, arg3)
if pfUI.disabled then return end
if pfUI.skin[name] then return end
func = BackwardsCompatRegister(func, arg3)
pfUI.skin[name] = func
@@ -349,6 +430,7 @@ function pfUI:LoadSkin(s)
end
pfUI:SetScript("OnEvent", function()
if pfUI.disabled then return end
-- make sure to initialize and set our fonts
-- each time an addon got loaded but only
@@ -362,7 +444,7 @@ pfUI:SetScript("OnEvent", function()
-- "@project-version@" until release tooling substitutes it — mark those
-- explicitly as "dev" instead of pretending they're a real numbered build.
local raw = tostring(GetAddOnMetadata(pfUI.name, "Version"))
if raw:find("@") then
if strfind(raw, "@") then
pfUI.version.major, pfUI.version.minor, pfUI.version.fix = 0, 0, 0
pfUI.version.string = "dev"
else
@@ -495,21 +577,4 @@ function pfUI.SetupCVars()
COMBAT_TEXT_SHOW_HONOR_GAINED = "1"
end
UIParentLoadAddOn("Blizzard_CombatText")
end
do -- RunMacroText
local obj = setmetatable({ ["GetText"] = function(self) return self.text end }, {
__index = function(tab,key)
local value = function() return end
rawset(tab,key,value)
return value
end
})
function RunMacroText(text)
obj.text = text
ChatEdit_ParseText(obj, 1)
end
end
_G.PLAYER_BUFF_START_ID = -1
end
+7 -5
View File
@@ -8,9 +8,11 @@
## SavedVariablesPerCharacter: pfUI_config, pfUI_init, pfUI_playerDB
## X-Website: https://github.com/brues-code/pfUI
# ClassicAPI-less fallback. ClassicAPI redirects this read to pfUI_Turtle.toc
# (Turtle clients) or pfUI_ClassicAPI.toc (everything else), so the client only
# ever reaches THIS file when the DLL is missing. Load the notice and nothing
# else.
pfUI.lua
API_Check.lua
init\env.xml
init\compat.xml
init\api.xml
init\libs.xml
init\skins.xml
init\modules.xml
-23
View File
@@ -1,23 +0,0 @@
## Interface: 11200
## Title: |cff33ffccpf|cffffffffUI
## Author: Shagu - modified by me0wg4ming & brues
## Notes: A complete user interface replacement.
## Notes-ruRU: Полная замена пользовательского интерфейса.
## Version: @project-version@
## SavedVariables: pfUI_profiles, pfUI_addon_profiles, pfUI_cache, pfUI_throttle
## SavedVariablesPerCharacter: pfUI_config, pfUI_init, pfUI_playerDB
## X-Website: https://github.com/brues-code/pfUI
# Selected by ClassicAPI on every non-Turtle client. Turtle clients get
# pfUI_Turtle.toc instead, which trades init\stock.xml for init\turtle.xml.
API_Check.lua
pfUI.lua
init\env.xml
init\stock.xml
init\api.xml
init\libs.xml
init\skins.xml
init\modules.xml
-24
View File
@@ -1,24 +0,0 @@
## Interface: 11200
## Title: |cff33ffccpf|cffffffffUI
## Author: Shagu - modified by me0wg4ming & brues
## Notes: A complete user interface replacement.
## Notes-ruRU: Полная замена пользовательского интерфейса.
## Version: @project-version@
## SavedVariables: pfUI_profiles, pfUI_addon_profiles, pfUI_cache, pfUI_throttle
## SavedVariablesPerCharacter: pfUI_config, pfUI_init, pfUI_playerDB
## X-Website: https://github.com/brues-code/pfUI
# Selected by ClassicAPI on Turtle WoW, where it wins over pfUI_ClassicAPI.toc.
# Same list with init\stock.xml swapped for init\turtle.xml: the modules, skins
# and vendor prices that only mean anything on a Turtle client.
API_Check.lua
pfUI.lua
init\env.xml
init\api.xml
init\libs.xml
init\skins.xml
init\modules.xml
init\turtle.xml