14 Commits

Author SHA1 Message Date
Brues b47df9272d Bump ClassicAPI minimum version to 1.5.11 2026-07-05 23:51:57 -05:00
Brues c0b717878d Always set OnClick handler for action buttons
Ensure the action button OnClick handler is always assigned. Previously SetScript("OnClick", ButtonClick) only ran when HookScript was missing; now HookScript is still added only if absent, but the OnClick script is set unconditionally so existing frames won't miss the click handler. Change is limited to modules/actionbar.lua.
2026-07-05 23:48:02 -05:00
Brues 31c95606d0 Refactor turtle/Nampower checks and libdebuff cleanup
Replace ad-hoc Turtle/Nampower detection with global TURTLE_WOW_VERSION and EventUtil startup flow. Remove legacy IsTurtleWoW and manual PLAYER_ENTERING_WORLD frame; use EventUtil.ContinueOnPlayerLogin. Clean up libdebuff by removing combo-point capture, GetEnhancedDebuffs API, and noisy startup messages; rely on Nampower/AURA_CAST and database fallback for durations. Fix tooltip compare shift handling (cache shift state and pass through). Update xpbar to use TURTLE_WOW_VERSION. Purpose: simplify startup, avoid duplicated logic, and rely on modern APIs for accurate durations.
2026-07-05 23:47:39 -05:00
Brues 3fe072c594 Route hooksecurefunc callers through pfUI.hooksecurefunc; global belongs to ClassicAPI
pfUI's Lua hooksecurefunc lived in pfUI.env and shadowed ClassicAPI's C
global for all pfUI code. Replace it with a thin pfUI.hooksecurefunc shim
that keeps the missing-target no-op our call sites rely on (ClassicAPI
errors on a nil target) and delegates the actual hook to _G.hooksecurefunc.

Migrated all 70 internal call sites (modules/libs/skins) to
pfUI.hooksecurefunc; bare hooksecurefunc now resolves to ClassicAPI's C
version everywhere. Dropped the unused prepend path and the orphaned
pfUI.hooks table.
2026-07-05 14:58:26 -05:00
Brues 9706a74d16 UNIT_INVENTORY_CHANGED -> PLAYER_EQUIPMENT_CHANGED 2026-07-05 14:32:25 -05:00
Brues f9b0b5983a Don't need to worry about caching player guid anymore 2026-07-04 22:46:55 -05:00
Brues 176e131d6b Update README.md 2026-07-04 20:46:19 -05:00
Brues a17229abb1 GetLootSlotItemLink should be GetLootSlotLink 2026-07-04 13:12:40 -05:00
Brues e0cf01772c Update FUNDING.yml 2026-07-03 23:27:18 -05:00
Brues c2d4106170 Update README.md 2026-07-03 22:59:29 -05:00
Brues dbfd337d42 Bump pfUI min to 1.5.8 2026-07-03 21:45:04 -05:00
Brues d834be9f0b Revert "nameplates: hide castbar on remote interrupt / caster death (#11)"
This reverts commit 703d7770ca.
2026-07-03 21:38:05 -05:00
Brues 82a07e1e35 share: rebuild profile export/import on C_EncodingUtil (CBOR+zlib+base64)
Export now diffs the config against defaults and emits
SerializeCBOR -> CompressString (zlib) -> EncodeBase64 with a "!pf1!"
prefix. Import reverses that into a plain table — no loadstring, so a
pasted profile is data and can't execute code. The Decode/Encode button
converts blob <-> editable JSON (SerializeJSON/DeserializeJSON) for
inspection and hand-edits.

Old-format strings still import: standard base64 via DecodeBase64, the
custom LZW decompressor kept import-only, and the resulting Lua source
runs in an EMPTY setfenv sandbox that can only assign its config table.
Decode on a legacy string yields the JSON view, so Encode re-emits it
as a new-format blob (migration path).

Roughly half the paste size of the old LZW format, C-speed instead of
the old bit-string base64 (which froze the client on large configs),
and the format is fully standard — external tools can decode profiles
with stock base64/zlib/CBOR libraries.

Requires ClassicAPI with the SerializeCBOR buffer-growth fix (payloads
over 256 bytes returned nil before it).
2026-07-03 21:19:07 -05:00
Brues 703d7770ca nameplates: hide castbar on remote interrupt / caster death (#11)
ClassicAPI's remote-cast cache is stamped from SMSG_SPELL_START and only
expires by computed end time — 1.12 keeps no per-unit interrupt record,
so an interrupted cast kept animating on the plate until its would-be
finish (BG flag caps being the loudest repro).

Nampower does surface the missing signal in Lua: SPELL_FAILED_OTHER
(casterGuid, spellId; fired from the SMSG_SPELL_FAILED_OTHER handler)
and UNIT_DIED (guid). Stamp a guid-keyed suppression time on either
event and have GetCastInfo drop any cast that started before the stamp;
a newer cast clears its unit's entry. Both castbar paths (dedicated
target frame + central loop) already funnel through GetCastInfo, so one
check covers them. The handler only stamps when the unit actually has a
tracked cast, and flags the plate via castUpdate for a same-tick hide.
2026-07-03 19:28:34 -05:00
53 changed files with 270 additions and 555 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
github: [shagu]
ko_fi: shagu
github: [brues]
buy_me_a_coffee: brues
+12 -4
View File
@@ -1,6 +1,6 @@
# pfUI - ClassicAPI Edition
[![Turtle WoW](https://img.shields.io/badge/Octo%20WoW-1.18.1-brightgreen.svg)](https://octowow.st/)
[![Octo WoW](https://img.shields.io/badge/Octo%20WoW-1.18.1-brightgreen.svg)](https://octowow.st/)
[![ClassicAPI](https://img.shields.io/badge/ClassicAPI-Required-purple.svg)](https://github.com/brues-code/ClassicAPI)
[![SuperWoW](https://img.shields.io/badge/SuperWoW-Required-purple.svg)](https://github.com/balakethelock/SuperWoW)
[![Nampower](https://img.shields.io/badge/Nampower-Required-purple.svg)](https://github.com/brues-code/nampower)
@@ -23,11 +23,19 @@ Since pfUI 6.0.0 includes integrations with client-side DLLs for enhanced functi
### [ClassicAPI](https://github.com/brues-code/ClassicAPI)
Provides:
- C_NamePlate - Event-driven nameplates (no more per-frame WorldFrame scanning) with real per-plate unit tokens and GUIDs
- C_UnitAuras - Replaces over 3k lines of hand-rolled aura tracking
- C_Spell - Replaces thousands of hardcoded spell names for each locale and powers castbar
- Instant Bag Sorting
- C_EquipmentSet
- Focus
- Real cast bars - Actual cast/channel timing, spellID and interrupt state for any unit (C_Spell.UnitCastingInfo)
- Focus - A genuine `focus` unit plus `/focus` and `/clearfocus` (FocusUnit / ClearFocus)
- C_EquipmentSet - Full Equipment Manager with GUID-tracked gear sets (tells apart duplicate/enchanted items)
- Instant Bag Sorting - C_Container.MoveItem / SwapItems instead of cursor pickup/drop
- Sell junk in one call - C_MerchantFrame.GetNumJunkItems / SellAllJunkItems
- Real item data - C_Item counts, quality, sell price and item info by ID
- GUID-based targeting - Nameplates, mouseover and focus resolve by GUID, not by name text
- Faster, safer profile sharing - Engine-side serialize/compress/base64 via C_EncodingUtil
- C_Timer - After / NewTicker replacing hand-rolled OnUpdate throttles
- Feign death, shapeshift and quest-item detection via real API calls
- Plenty other functions
### [SuperWoW](https://github.com/balakethelock/SuperWoW)
-4
View File
@@ -28,10 +28,6 @@ function pfUI.api.HasNampower()
return GetNampowerVersion and true or false
end
function pfUI.api.IsTurtleWoW()
return C_Spell.GetSpellTexture(46050) == "Interface\\Icons\\Trade_Survival"
end
-- [ GetUnitDistance ]
-- Returns distance to unit using best available method
-- 'unit1' [string] first unit (default: "player")
+2 -2
View File
@@ -1014,7 +1014,7 @@ function pfUI.uf.OnEvent()
-- Raid frames: update_full is set by raid.lua GUID tracker
elseif this.label == "pet" and event == "UNIT_PET" then
this.update_full = true
elseif this.label == "player" and (event == "PLAYER_AURAS_CHANGED" or event == "UNIT_INVENTORY_CHANGED") then
elseif this.label == "player" and (event == "PLAYER_AURAS_CHANGED" or event == "PLAYER_EQUIPMENT_CHANGED") then
this.update_aura = true
elseif this.label == "pet" and event == "UNIT_HAPPINESS" then
this.update_full = true
@@ -1552,7 +1552,7 @@ function pfUI.uf:EnableEvents()
f:RegisterEvent("UNIT_FACTION")
f:RegisterEvent("UNIT_AURA") -- frame=buff, frame=debuff
f:RegisterEvent("PLAYER_AURAS_CHANGED") -- label=player && frame=buff
f:RegisterEvent("UNIT_INVENTORY_CHANGED") -- label=player && frame=buff
f:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") -- label=player && frame=buff (ClassicAPI: weapon-enchant buffs)
f:RegisterEvent("PARTY_MEMBERS_CHANGED") -- label=party, frame=leaderIcon
f:RegisterEvent("PARTY_LEADER_CHANGED") -- frame=leaderIcon
f:RegisterEvent("RAID_ROSTER_UPDATE") -- label=raidIcon
+10 -26
View File
@@ -28,32 +28,16 @@ ACTIONBAR_SECURE_TEMPLATE_BUTTON = nil
UNITFRAME_SECURE_TEMPLATE = nil
--[[ Vanilla API Extensions ]]--
function hooksecurefunc(tbl, name, func, prepend)
if type(tbl) == "string" then
prepend, func, name, tbl = func, name, tbl, _G
end
if not tbl or not tbl[name] then return end
pfUI.hooks[tostring(func)] = {}
pfUI.hooks[tostring(func)]["old"] = tbl[name]
pfUI.hooks[tostring(func)]["new"] = func
if prepend then
pfUI.hooks[tostring(func)]["function"] = function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16)
pfUI.hooks[tostring(func)]["new"](a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16)
return pfUI.hooks[tostring(func)]["old"](a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16)
end
else
pfUI.hooks[tostring(func)]["function"] = function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16)
local ok, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16 = pcall(pfUI.hooks[tostring(func)]["old"], a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16)
if not ok then return end
pfUI.hooks[tostring(func)]["new"](a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16)
return r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16
end
end
tbl[name] = pfUI.hooks[tostring(func)]["function"]
-- Safe post-hook helper. The global `hooksecurefunc` belongs to ClassicAPI
-- (its C implementation); this wrapper only adds pfUI's missing-target guard:
-- ClassicAPI errors when target[name] isn't a function, whereas a lot of our
-- call sites hook optional/late-loaded frames and rely on a silent no-op.
-- Normalizes the string form, skips when the target is absent, then delegates
-- to the C version (uncapped args, callback-pcall, taint parity).
function pfUI.hooksecurefunc(tbl, name, func)
if type(tbl) == "string" then tbl, name, func = _G, tbl, name end
if not tbl or type(tbl[name]) ~= "function" then return end
return _G.hooksecurefunc(tbl, name, func)
end
do -- GetItemInfo
+18 -145
View File
@@ -14,7 +14,7 @@ setfenv(1, pfUI:GetEnvironment())
-- The public per-aura readers (UnitDebuff, UnitOwnDebuff) were retired in favor
-- of ClassicAPI's C_UnitAuras (which now provides sourceUnit/sourceGUID and
-- non-player expirationTime). What remains in libdebuff is the cast-event
-- bookkeeping consumed by GetBestAuraCast / GetEnhancedDebuffs and the
-- bookkeeping consumed by GetBestAuraCast (libpredict HoT tracking) and the
-- libdebuff_*_hooks broadcast surface (subscribers in actionbar / swingtimer
-- / libtotem react to SPELL_GO and SPELL_FAILED).
@@ -43,13 +43,7 @@ if GetNampowerVersion then
end
end
-- Nampower startup check: show version info and ensure CVars are set.
-- Runs the frame after PLAYER_ENTERING_WORLD so Nampower has finished initializing.
local nampowerCheckFrame = CreateFrame("Frame")
nampowerCheckFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
nampowerCheckFrame:SetScript("OnEvent", function()
this:UnregisterAllEvents()
this:SetScript("OnEvent", nil)
EventUtil.ContinueOnPlayerLogin(function()
RunNextFrame(function()
if GetNampowerVersion then
@@ -58,8 +52,6 @@ nampowerCheckFrame:SetScript("OnEvent", function()
local versionString = major .. "." .. minor .. "." .. patch
if major > 3 or (major == 3 and minor > 0) or (major == 3 and minor == 0 and patch >= 0) then
DEFAULT_CHAT_FRAME:AddMessage("|cff33ff99[libdebuff]|r Nampower v" .. versionString .. " detected - GetUnitField mode enabled!")
if SetCVar and GetCVar then
local cvarsToEnable = {
"NP_EnableSpellStartEvents",
@@ -89,8 +81,6 @@ nampowerCheckFrame:SetScript("OnEvent", function()
if enabledCount > 0 then
DEFAULT_CHAT_FRAME:AddMessage("|cff33ff99[libdebuff]|r Enabled " .. enabledCount .. " Nampower CVars")
elseif alreadyEnabledCount == table.getn(cvarsToEnable) then
DEFAULT_CHAT_FRAME:AddMessage("|cff33ff99[libdebuff]|r All required Nampower CVars already enabled")
end
if failedCount > 0 then
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc00[libdebuff]|r Warning: Could not check/set " .. failedCount .. " CVars")
@@ -202,10 +192,6 @@ pfUI.libdebuff_spell_cast_hooks = pfUI.libdebuff_spell_cast_hooks or {}
pfUI.libdebuff_downrank_blocked_hooks = pfUI.libdebuff_downrank_blocked_hooks or {}
local AURA_CAST_DEDUPE_WINDOW = 0.1 -- Ignore duplicates within 100ms
-- Captured combo points from SPELL_CAST_EVENT (before client consumes them)
-- SPELL_CAST_EVENT fires BEFORE UnitAura updates, so GetComboPoints() still works
local capturedCP = nil
-- Pending cast info for libpredict (heal prediction target tracking)
-- SPELL_CAST_EVENT fires with targetGuid BEFORE SPELLCAST_START,
-- which allows libpredict to know the correct target for queued casts.
@@ -278,50 +264,10 @@ local debuffOverwritePairs = {
["Demoralizing Roar"] = "Demoralizing Shout",
}
-- Combopoint-based abilities: Only show timers for OUR casts
-- Format: [spellName] = { base = N, perCP = N }
-- Duration formula: duration = base + combopoints * perCP
local combopointAbilities = {
-- Druid
["Rip"] = { base = 8, perCP = 2 },
-- Rogue
["Rupture"] = { base = 6, perCP = 2 },
["Kidney Shot"] = { base = 1, perCP = 1 },
["Slice and Dice"] = { base = 9, perCP = 3 },
["Expose Armor"] = { base = 30, perCP = 0 }, -- fixed 30s
}
-- ============================================================================
-- HELPER FUNCTIONS
-- ============================================================================
-- Check if spell is a combo-point ability
local function IsComboPointAbility(spellName)
if not spellName then return false end
return combopointAbilities[spellName] ~= nil
end
-- Get combo-point spell data (base duration and per-CP bonus)
local function GetComboPointData(spellName)
if not spellName then return nil, nil end
local cpData = combopointAbilities[spellName]
if cpData then
return cpData.base, cpData.perCP
end
return nil, nil
end
-- Player GUID Cache
local playerGUID = nil
local function GetPlayerGUID()
if not playerGUID and UnitGUID then
local guid = UnitGUID("player")
playerGUID = guid
end
return playerGUID
end
-- Debug Stats
pfUI.libdebuff_debugstats = pfUI.libdebuff_debugstats or {
enabled = false,
@@ -461,7 +407,7 @@ local function GetSlotCaster(guid, auraSlot, spellName)
end
-- Fallback: Check ownDebuffs
local myGuid = GetPlayerGUID()
local myGuid = GetPlayerGuid()
if ownDebuffs[guid] and ownDebuffs[guid][spellName] then
return myGuid, true
end
@@ -652,16 +598,7 @@ function libdebuff:GetDuration(effect, rank)
local rank = L["debuffs"][effect][rank] and rank or libdebuff:GetMaxRank(effect)
local duration = L["debuffs"][effect][rank]
if effect == L["dyndebuffs"]["Rupture"] then
local cp = GetComboPoints() or 0
duration = duration + cp*2
elseif effect == L["dyndebuffs"]["Kidney Shot"] then
local cp = GetComboPoints() or 0
duration = duration + cp*1
elseif effect == "Rip" or effect == L["dyndebuffs"]["Rip"] then
local cp = GetComboPoints() or 0
duration = 8 + cp*2
elseif effect == L["dyndebuffs"]["Demoralizing Shout"] then
if effect == L["dyndebuffs"]["Demoralizing Shout"] then
local _,_,_,_,count = GetTalentInfo(2,1)
if count and count > 0 then duration = duration + ( duration / 100 * (count*10)) end
elseif effect == L["dyndebuffs"]["Shadow Word: Pain"] then
@@ -798,7 +735,7 @@ function libdebuff:GetBestAuraCast(guid, spellName)
local data = ownDebuffs[guid][spellName]
local timeleft = (data.startTime + data.duration) - GetTime()
if timeleft > 0 then
return data.startTime, data.duration, timeleft, data.rank, GetPlayerGUID()
return data.startTime, data.duration, timeleft, data.rank, GetPlayerGuid()
end
end
@@ -825,33 +762,6 @@ function libdebuff:GetBestAuraCast(guid, spellName)
return nil
end
-- ============================================================================
-- API: GetEnhancedDebuffs (for external modules)
-- ============================================================================
function libdebuff:GetEnhancedDebuffs(targetGUID)
if not targetGUID then return nil end
local result = {}
if ownDebuffs[targetGUID] then
local myGuid = GetPlayerGUID()
for spellName, data in pairs(ownDebuffs[targetGUID]) do
local timeleft = (data.startTime + data.duration) - GetTime()
if timeleft > 0 then
result[spellName] = result[spellName] or {}
result[spellName][myGuid] = {
startTime = data.startTime,
duration = data.duration,
texture = data.texture,
rank = data.rank
}
end
end
end
return result
end
-- ============================================================================
-- NAMPOWER EVENT HANDLING
-- ============================================================================
@@ -883,7 +793,7 @@ if hasNampower then
-- Carnage triggered! Refresh Rip & Rake
local guid = carnageState.targetGuid
local refreshTime = GetTime()
local myGuid = GetPlayerGUID()
local myGuid = GetPlayerGuid()
-- Refresh in ownDebuffs - only if timer still active
if ownDebuffs[guid] then
@@ -976,14 +886,8 @@ if hasNampower then
end
end
end
elseif event == "PLAYER_ENTERING_WORLD" then
GetPlayerGUID()
elseif event == "PLAYER_ENTERING_WORLD" or event == "PLAYER_TALENT_UPDATE" then
UpdateCarnageRank()
elseif event == "PLAYER_TALENT_UPDATE" then
UpdateCarnageRank()
elseif event == "UNIT_HEALTH" then
local guid = arg1
if guid and UnitIsDead and UnitIsDead(guid) then
@@ -1078,7 +982,7 @@ if hasNampower then
local selfdebuffMode = pfUI_config and pfUI_config.buffbar and
pfUI_config.buffbar.tdebuff and pfUI_config.buffbar.tdebuff.selfdebuff == "1"
if selfdebuffMode then
local myGuid2 = GetPlayerGUID()
local myGuid2 = GetPlayerGuid()
if casterGuid == myGuid2 then
local duration = libdebuff:GetDuration(spellName, castRank) or 0
if duration > 0 then
@@ -1108,7 +1012,7 @@ if hasNampower then
end
-- Store rank for our casts
local myGuid = GetPlayerGUID()
local myGuid = GetPlayerGuid()
if casterGuid == myGuid then
lastCastRanks[spellName] = {
rank = castRank,
@@ -1181,11 +1085,6 @@ if hasNampower then
pfUI.libpredict_pending_cast.time = nil
end
-- Only capture CPs for combo-point abilities
if spellName and IsComboPointAbility(spellName) then
capturedCP = GetComboPoints() or 0
end
-- Fire registered SPELL_CAST_EVENT hooks
if pfUI.libdebuff_spell_cast_hooks then
for _, fn in pairs(pfUI.libdebuff_spell_cast_hooks) do
@@ -1233,37 +1132,17 @@ if hasNampower then
local duration = durationMs and (durationMs / 1000) or 0
local startTime = GetTime()
local myGuid = GetPlayerGUID()
local myGuid = GetPlayerGuid()
local isOurs = (myGuid and casterGuid == myGuid)
if debugStats.enabled and isOurs then
debugStats.aura_cast = debugStats.aura_cast + 1
end
-- Combo-point abilities: Calculate duration based on CPs used
if IsComboPointAbility(spellName) then
if isOurs then
-- OWN casts: use captured CPs from SPELL_CAST_EVENT (if available)
local cp = capturedCP or 0
local base, perCP = GetComboPointData(spellName)
if base and perCP then
duration = base + cp * perCP
else
-- Fallback to legacy database
duration = libdebuff:GetDuration(spellName, rankNum)
end
capturedCP = nil -- consumed
else
-- OTHER players: CP unknown, no timer (except Expose Armor = fixed 30s)
local base, perCP = GetComboPointData(spellName)
if perCP and perCP == 0 and base then
duration = base -- fixed duration (Expose Armor)
else
duration = 0 -- CP unknown for other players
end
end
elseif duration == 0 then
-- Non-CP managed spells: use database if AURA_CAST returned 0
-- Duration comes from nampower's AURA_CAST event. ClassicAPI's
-- C_UnitAuras now resolves combo-scaled durations server-side, so
-- libdebuff only needs the database fallback when AURA_CAST reports 0.
if duration == 0 then
duration = libdebuff:GetDuration(spellName, rankNum) or 0
end
@@ -1365,15 +1244,12 @@ if hasNampower then
-- Notify unitframes of debuff updates (UNIT_AURA doesn't fire on refreshes!)
-- Check player
if UnitGUID("player") then
local playerGuid = UnitGUID("player")
if playerGuid == targetGuid and pfPlayer then
pfPlayer.update_aura = true
end
if IsPlayerGuid(targetGuid) and pfPlayer then
pfPlayer.update_aura = true
end
-- Check target
if UnitGUID("target") then
if UnitExists("target") then
local tarUnitGUID = UnitGUID("target")
if tarUnitGUID == targetGuid and pfTarget then
pfTarget.update_aura = true
@@ -1520,7 +1396,7 @@ if hasNampower then
end
end
local myGuid = GetPlayerGUID()
local myGuid = GetPlayerGuid()
local isOurs = (myGuid and casterGuid == myGuid)
-- Fallback: Check ownDebuffs timing
@@ -1555,7 +1431,6 @@ if hasNampower then
-- CRITICAL FIX: Update ownDebuffs here too for refresh timing!
-- This prevents the gap between DEBUFF_REMOVED and AURA_CAST where buffwatch shows nothing
if isOurs and casterGuid then
local myGuid = GetPlayerGUID()
if myGuid and casterGuid == myGuid then
-- Check if we have timer data from allAuraCasts
if allAuraCasts[guid] and allAuraCasts[guid][spellName] and allAuraCasts[guid][spellName][casterGuid] then
@@ -1809,5 +1684,3 @@ _G.SlashCmdList["MEMCHECK"] = function()
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00No ownSlots/allSlots (eliminated by GetUnitField approach!)|r")
DEFAULT_CHAT_FRAME:AddMessage("|cff00ffff============================================================|r")
end
DEFAULT_CHAT_FRAME:AddMessage("|cff33ff99[libdebuff]|r GetUnitField Edition loaded!")
+5 -8
View File
@@ -818,7 +818,7 @@ local hotsetbonus = libtipscan:GetScanner("hotsetbonus")
resetcache:RegisterEvent("PLAYER_ENTERING_WORLD")
resetcache:RegisterEvent("LEARNED_SPELL_IN_TAB")
resetcache:RegisterEvent("CHARACTER_POINTS_CHANGED")
resetcache:RegisterEvent("UNIT_INVENTORY_CHANGED")
resetcache:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
resetcache:SetScript("OnEvent", function()
if event == "PLAYER_ENTERING_WORLD" then
-- load and initialize previous caches of spell amounts
@@ -829,10 +829,7 @@ resetcache:SetScript("OnEvent", function()
cache = pfUI_cache["prediction"][realm][player]["heals"]
end
if event == "UNIT_INVENTORY_CHANGED" or "PLAYER_ENTERING_WORLD" then
-- skip non-player events
if arg1 and arg1 ~= "player" then return end
if event == "PLAYER_EQUIPMENT_CHANGED" or event == "PLAYER_ENTERING_WORLD" then
local gear = ""
for id = 1, 18 do
gear = gear .. (GetInventoryItemLink("player",id) or "")
@@ -902,7 +899,7 @@ local INSTANT_HOT_COOLDOWN = 1.0 -- 1 Sekunde Cooldown (GCD ist 1.5s)
local pendingHots = {}
-- Gather Data by User Actions
hooksecurefunc("CastSpell", function(id, bookType)
pfUI.hooksecurefunc("CastSpell", function(id, bookType)
if not libpredict.sender.enabled then return end
local effect, rank = libspell.GetSpellInfo(id, bookType)
if not effect then return end
@@ -955,7 +952,7 @@ hooksecurefunc("CastSpell", function(id, bookType)
end
end)
hooksecurefunc("CastSpellByName", function(effect, target)
pfUI.hooksecurefunc("CastSpellByName", function(effect, target)
if not libpredict.sender.enabled then return end
local effect, rank = libspell.GetSpellInfo(effect)
if not effect then return end
@@ -1019,7 +1016,7 @@ hooksecurefunc("CastSpellByName", function(effect, target)
end
end)
hooksecurefunc("UseAction", function(slot, target, selfcast)
pfUI.hooksecurefunc("UseAction", function(slot, target, selfcast)
if not libpredict.sender.enabled then return end
if not IsCurrentAction(slot) then return end
local kind, id = GetActionInfo(slot)
+1 -1
View File
@@ -54,6 +54,6 @@ end
pfUI.api.libtooltip = libtooltip
hooksecurefunc(GameTooltip, "SetBagItem", function(self, container, slot)
pfUI.hooksecurefunc(GameTooltip, "SetBagItem", function(self, container, slot)
_, libtooltip.itemCount = GetContainerItemInfo(container, slot)
end)
+3 -3
View File
@@ -241,14 +241,14 @@ pfUI.libdebuff_spell_go_hooks["libtotem"] = function(spellId)
end
-- Hook CastSpellByName to store pending name/icon per slot
hooksecurefunc("CastSpellByName", function(effect, target)
pfUI.hooksecurefunc("CastSpellByName", function(effect, target)
local name, rank, icon, _, _, _, spellId = libspell.GetSpellInfo(effect)
if not name then return end
libtotem:CheckAddQueue(name, rank, icon, spellId)
end)
-- Hook CastSpell to store pending name/icon per slot
hooksecurefunc("CastSpell", function(id, bookType)
pfUI.hooksecurefunc("CastSpell", function(id, bookType)
if not id or not bookType then return end
if bookType ~= BOOKTYPE_SPELL and bookType ~= BOOKTYPE_PET then return end
local name, rank, icon, _, _, _, spellId = libspell.GetSpellInfo(id, bookType)
@@ -259,7 +259,7 @@ end)
-- Hook UseAction. GetActionInfo + GetMacroSpell give us the spellID
-- directly for both spell-action and macro-action slots, so the
-- tooltip-scan fallback (and the "no spellId available" caveat) goes away.
hooksecurefunc("UseAction", function(slot, target, selfcast)
pfUI.hooksecurefunc("UseAction", function(slot, target, selfcast)
if not IsCurrentAction(slot) then return end
local kind, id = GetActionInfo(slot)
local name, rank, spellID
+2 -4
View File
@@ -1013,10 +1013,8 @@ pfUI:RegisterModule("actionbar", function ()
-- no button available, create a new one
if not exists then
-- prepare the button for vanilla
if not f.HookScript then
f.HookScript = HookScript
f:SetScript("OnClick", ButtonClick)
end
if not f.HookScript then f.HookScript = HookScript end
f:SetScript("OnClick", ButtonClick)
if bar ~= 11 then
f:RegisterForDrag("LeftButton", "RightButton")
+1 -1
View File
@@ -159,7 +159,7 @@ pfUI:RegisterModule("buff", function ()
pfUI.buff = CreateFrame("Frame", "pfGlobalBuffFrame", UIParent)
pfUI.buff:RegisterEvent("PLAYER_AURAS_CHANGED")
pfUI.buff:RegisterEvent("UNIT_INVENTORY_CHANGED")
pfUI.buff:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
pfUI.buff:RegisterEvent("UNIT_MODEL_CHANGED")
pfUI.buff:RegisterEvent("BUFF_UPDATE_DURATION_SELF")
pfUI.buff:RegisterEvent("DEBUFF_UPDATE_DURATION_SELF")
+1 -1
View File
@@ -487,7 +487,7 @@ pfUI:RegisterModule("castbar", function ()
-- (the config knob is read at event time so toggling takes effect on the
-- next craft without a /reload). DoTradeSkill is synchronous; the server
-- roundtrip to SPELLCAST_START gives us plenty of time after this hook.
hooksecurefunc("DoTradeSkill", function(index, num)
pfUI.hooksecurefunc("DoTradeSkill", function(index, num)
if pfUI.castbar.player then
pfUI.castbar.player.pendingTradeskillCount = tonumber(num) or 1
end
+2 -2
View File
@@ -24,7 +24,7 @@ pfUI:RegisterModule("chat", function ()
end
end
hooksecurefunc("UnitPopup_OnClick", function(self)
pfUI.hooksecurefunc("UnitPopup_OnClick", function(self)
if this.value == "IGNORE_PLAYER" then
AddIgnore(_G[UIDROPDOWNMENU_INIT_MENU].name)
end
@@ -449,7 +449,7 @@ pfUI:RegisterModule("chat", function ()
end
end
hooksecurefunc("FCF_SaveDock", pfUI.chat.RefreshChat)
pfUI.hooksecurefunc("FCF_SaveDock", pfUI.chat.RefreshChat)
if C.chat.global.tabmouse == "1" then
pfUI.chat.mouseovertab = CreateFrame("Frame")
+1 -1
View File
@@ -136,5 +136,5 @@ pfUI:RegisterModule("cooldown", function ()
-- vanilla does not have a cooldown frame type, so we hook the
-- regular SetTimer function that each one is calling.
hooksecurefunc("CooldownFrame_SetTimer", SetCooldown)
pfUI.hooksecurefunc("CooldownFrame_SetTimer", SetCooldown)
end)
+6 -5
View File
@@ -3,8 +3,9 @@ pfUI:RegisterModule("eqcompare", function ()
local function ShowCompareItem(self, link, shift)
self = self or GameTooltip
shift = shift or IsShiftKeyDown()
if not link or (not IsShiftKeyDown() and (C.tooltip.compare.showalways ~= "1" or C_Item.IsEquippedItem(link))) then
if not link or (not shift and (C.tooltip.compare.showalways ~= "1" or C_Item.IsEquippedItem(link))) then
return
end
@@ -88,7 +89,7 @@ pfUI:RegisterModule("eqcompare", function ()
local prevMerchant = ShoppingTooltip1.SetMerchantCompareItem
local function SetMerchantCompareItem(self, index, compareItem)
if C.tooltip.compare.basestats == "1" and compareItem == 1 then
ShowCompareItem(nil, GetMerchantItemLink(index))
ShowCompareItem(nil, GetMerchantItemLink(index), 1)
return false
end
return prevMerchant and prevMerchant(self, index, compareItem)
@@ -97,7 +98,7 @@ pfUI:RegisterModule("eqcompare", function ()
local prevAuction = ShoppingTooltip1.SetAuctionCompareItem
local function SetAuctionCompareItem(self, type, index, compareItem)
if C.tooltip.compare.basestats == "1" and compareItem == 1 then
ShowCompareItem(nil, GetAuctionItemLink(type, index))
ShowCompareItem(nil, GetAuctionItemLink(type, index), 1)
return false
end
return prevAuction and prevAuction(self, type, index, compareItem)
@@ -110,7 +111,7 @@ pfUI:RegisterModule("eqcompare", function ()
local TooltipHooks = {
SetLootRollItem = GetLootRollItemLink,
SetLootItem = GetLootSlotItemLink,
SetLootItem = GetLootSlotLink,
SetQuestLogItem = GetQuestLogItemLink,
SetQuestItem = GetQuestItemLink,
SetHyperlink = function(link) return link end,
@@ -139,7 +140,7 @@ pfUI:RegisterModule("eqcompare", function ()
local function HookTooltip(tooltip)
for setter, getter in pairs(TooltipHooks) do
_G['hooksecurefunc'](tooltip, setter, makeHook(getter))
pfUI.hooksecurefunc(tooltip, setter, makeHook(getter))
end
end
+2 -3
View File
@@ -1048,11 +1048,10 @@ pfUI:RegisterModule("equipmentmanager", function()
events:RegisterEvent("EQUIPMENT_SETS_CHANGED")
events:RegisterEvent("EQUIPMENT_SWAP_FINISHED")
events:RegisterEvent("EQUIPMENT_SWAP_PENDING")
events:RegisterEvent("BAG_UPDATE_DELAYED") -- ClassicAPI debounced; ~4x fewer refreshes than BAG_UPDATE
events:RegisterEvent("UNIT_INVENTORY_CHANGED")
events:RegisterEvent("BAG_UPDATE_DELAYED")
events:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
events:SetScript("OnEvent", function()
if not frame:IsShown() then return end
if event == "UNIT_INVENTORY_CHANGED" and arg1 ~= "player" then return end
pfUI.equipmentmanager.Refresh()
end)
+2 -2
View File
@@ -150,7 +150,7 @@ pfUI:RegisterSkin("Friends", function ()
end
-- set positions
hooksecurefunc("WhoList_Update", function()
pfUI.hooksecurefunc("WhoList_Update", function()
for i = 1, WHOS_TO_DISPLAY do
local level = _G["WhoFrameButton"..i.."Level"]
level:ClearAllPoints()
@@ -231,7 +231,7 @@ pfUI:RegisterSkin("Friends", function ()
end
-- set positions
hooksecurefunc("GuildStatus_Update", function()
pfUI.hooksecurefunc("GuildStatus_Update", function()
for i = 1, GUILDMEMBERS_TO_DISPLAY do
local level = _G["GuildFrameButton"..i.."Level"]
level:ClearAllPoints()
+1 -1
View File
@@ -86,7 +86,7 @@ pfUI:RegisterModule("gm", function ()
-- pet dropdown
-- table.insert(UnitPopupMenus["PET"], "GM_HEADER")
hooksecurefunc("UnitPopup_OnClick", function()
pfUI.hooksecurefunc("UnitPopup_OnClick", function()
local dropdownFrame = _G[UIDROPDOWNMENU_INIT_MENU]
local button = this.value
local unit = dropdownFrame.unit
+1 -10
View File
@@ -13,15 +13,6 @@ pfUI:RegisterModule("innervatecall", function ()
local INNERVATE_SPELLID = 29166
-- Cache player GUID
local playerGuid = nil
local function GetPlayerGuid()
if not playerGuid and UnitGUID then
playerGuid = UnitGUID("player")
end
return playerGuid
end
-- GUID → name resolution for the target. UnitTokenFromGUID walks the
-- engine's known unit tokens (player, party, raid, target, ...) and
-- returns the first one currently bound to the GUID, so we don't have
@@ -75,7 +66,7 @@ pfUI:RegisterModule("innervatecall", function ()
if spellId ~= INNERVATE_SPELLID then return end
-- Only announce our own casts
if casterGuid ~= GetPlayerGuid() then return end
if not IsPlayerGuid(casterGuid) then return end
-- Resolve target name from GUID
local targetName = ResolveTargetName(targetGuid) or "Unknown"
+1 -1
View File
@@ -41,7 +41,7 @@ pfUI:RegisterModule("itemcount", function ()
end
end)
hooksecurefunc("SetItemRef", function()
pfUI.hooksecurefunc("SetItemRef", function()
if ItemRefTooltip:HasItem() then
local _, _, id = ItemRefTooltip:GetItem()
if id then AddCounts(ItemRefTooltip, id) end
+2 -2
View File
@@ -392,7 +392,7 @@ pfUI:RegisterModule("loot", function ()
end
pfUI.loot:RemoveMasterlootMenus() -- remove then add to ensure no duplicate menus
pfUI.loot:AddMasterLootMenus()
hooksecurefunc("UnitPopup_OnClick",function()
pfUI.hooksecurefunc("UnitPopup_OnClick",function()
local dropdownFrame = _G[UIDROPDOWNMENU_INIT_MENU]
if not dropdownFrame then return end
local button = this.value
@@ -405,7 +405,7 @@ pfUI:RegisterModule("loot", function ()
end
end
end)
hooksecurefunc("UnitPopup_HideButtons",function()
pfUI.hooksecurefunc("UnitPopup_HideButtons",function()
local dropdownFrame = _G[UIDROPDOWNMENU_INIT_MENU]
local unit = dropdownFrame.unit
local name = dropdownFrame.name
+4 -4
View File
@@ -125,13 +125,13 @@ pfUI:RegisterModule("mapcolors", function ()
-- WorldMap
Initialize('WorldMap')
hooksecurefunc('WorldMapButton_OnUpdate', function()
pfUI.hooksecurefunc('WorldMapButton_OnUpdate', function()
if ( this.tick or .5) > GetTime() then return else this.tick = GetTime() + .5 end
UpdateUnitFrames('WorldMap')
end)
if C.appearance.worldmap.colornames == "1" then
hooksecurefunc('WorldMapUnit_OnEnter', function()
pfUI.hooksecurefunc('WorldMapUnit_OnEnter', function()
if ( this.tick or .5) > GetTime() then return else this.tick = GetTime() + .5 end
UpdateUnitColors('WorldMap', WorldMapTooltip)
end)
@@ -141,13 +141,13 @@ pfUI:RegisterModule("mapcolors", function ()
HookAddonOrVariable("Blizzard_BattlefieldMinimap", function()
Initialize('BattlefieldMinimap')
hooksecurefunc('BattlefieldMinimap_OnUpdate', function()
pfUI.hooksecurefunc('BattlefieldMinimap_OnUpdate', function()
if ( this.tick or .5) > GetTime() then return else this.tick = GetTime() + .5 end
UpdateUnitFrames('BattlefieldMinimap')
end)
if C.appearance.worldmap.colornames == "1" then
hooksecurefunc('BattlefieldMinimapUnit_OnEnter', function()
pfUI.hooksecurefunc('BattlefieldMinimapUnit_OnEnter', function()
if ( this.tick or .5) > GetTime() then return else this.tick = GetTime() + .5 end
UpdateUnitColors('BattlefieldMinimap', GameTooltip)
end)
+1 -1
View File
@@ -58,7 +58,7 @@ pfUI:RegisterModule("minimap", function ()
pfUI.minimap:UpdateConfig()
hooksecurefunc("ToggleMinimap", function()
pfUI.hooksecurefunc("ToggleMinimap", function()
if pfUI.farmmap and pfUI.farmmap:IsShown() then
Minimap:Hide()
return
-7
View File
@@ -100,12 +100,6 @@ pfUI:RegisterModule("nameplates", function ()
-- PERF: visiblePlateCount maintained event-driven (NAME_PLATE_UNIT_ADDED/_REMOVED)
local visiblePlateCount = 0
-- wipe polyfill
local wipe = wipe or function(t) for k in pairs(t) do t[k] = nil end end
-- Player GUID for filtering
local PlayerGUID = UnitGUID("player")
-- ============================================================================
-- OPTIMIZATION: Config caching
-- ============================================================================
@@ -492,7 +486,6 @@ end
elseif event == "PLAYER_ENTERING_WORLD" or event == "ZONE_CHANGED_NEW_AREA" then
if event == "PLAYER_ENTERING_WORLD" then
_, PlayerGUID = UnitExists("player")
CacheConfig()
this:SetGameVariables()
RebuildRaidGuidCache()
+2 -3
View File
@@ -424,7 +424,8 @@ pfUI:RegisterModule("panel", function()
widget:RegisterEvent("PLAYER_REGEN_ENABLED")
widget:RegisterEvent("PLAYER_DEAD")
widget:RegisterEvent("PLAYER_UNGHOST")
widget:RegisterEvent("UNIT_INVENTORY_CHANGED")
widget:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") -- ClassicAPI: equip/unequip changes total durability
widget:RegisterEvent("UPDATE_INVENTORY_DURABILITY") -- ClassicAPI: combat wear / repair
widget.Click = function() ToggleCharacter("PaperDollFrame") end
widget.Tooltip = function()
@@ -456,8 +457,6 @@ pfUI:RegisterModule("panel", function()
end
end
widget:SetScript("OnEvent", function()
if event == "UNIT_INVENTORY_CHANGED" and arg1 ~= "player" then return end
local totalCurr, totalMax = 0, 0
for id = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
local cur, max = GetInventoryItemDurability(id)
+1 -1
View File
@@ -141,7 +141,7 @@ pfUI:RegisterModule("player", function ()
end
end
hooksecurefunc("UnitPopup_OnClick", function()
pfUI.hooksecurefunc("UnitPopup_OnClick", function()
local button = this.value
if button == "RESET_INSTANCES_FIX" then
StaticPopup_Show("CONFIRM_RESET_INSTANCES")
+1 -1
View File
@@ -95,7 +95,7 @@ pfUI:RegisterModule("questitem", function ()
-- itemref tooltip (chat link clicks): hooksecurefunc runs after SetItemRef
-- populates ItemRefTooltip, so we just read the item back out of the tooltip
-- instead of re-parsing the "item:NNN" out of the link string.
hooksecurefunc("SetItemRef", function()
pfUI.hooksecurefunc("SetItemRef", function()
if IsModifierKeyDown() then return end
if ItemRefTooltip:HasItem() then
local _, _, id = ItemRefTooltip:GetItem()
+1 -1
View File
@@ -164,7 +164,7 @@ pfUI:RegisterModule("raid", function ()
end
end
hooksecurefunc("UnitPopup_OnClick", function()
pfUI.hooksecurefunc("UnitPopup_OnClick", function()
local dropdownFrame = UIDROPDOWNMENU_INIT_MENU and _G[UIDROPDOWNMENU_INIT_MENU]
if not dropdownFrame then return end
local button = this.value
+1 -1
View File
@@ -40,7 +40,7 @@ pfUI:RegisterModule("sellvalue", function ()
end
end)
hooksecurefunc("SetItemRef", function()
pfUI.hooksecurefunc("SetItemRef", function()
if IsModifierKeyDown() then return end
if ItemRefTooltip:HasItem() then
local _, _, id = ItemRefTooltip:GetItem()
+131 -194
View File
@@ -1,93 +1,78 @@
pfUI:RegisterModule("share", function ()
local function serialize(tbl, comp, name, ignored, spacing)
local spacing = spacing or ""
local match = nil
local tname = ( spacing == "" and "" or "[\"" ) .. name .. ( spacing == "" and "" or "\"]" )
local str = spacing .. tname .. " = {\n"
-- Profile sharing rides ClassicAPI's C_EncodingUtil:
-- export: diff vs defaults -> SerializeCBOR -> CompressString (zlib)
-- -> EncodeBase64, prefixed with the format magic
-- import: the reverse, into a plain table — no loadstring, so a
-- pasted profile can't execute code
-- The Decode/Encode button converts between the transport blob and an
-- editable JSON view of the same table.
local MAGIC = "!pf1!"
-- Deep-diff `tbl` against `default`, keeping only changed or added
-- values. `ignored` keys are skipped at the top level only (matches the
-- old serializer: "position"/"disabled" when Ignore Layout is checked).
-- Returns nil when nothing differs.
local function DiffConfig(tbl, default, ignored)
local diff = nil
for k, v in pairs(tbl) do
if not ( ignored[k] and spacing == "" ) and ( not comp or not comp[k] or comp[k] ~= tbl[k] ) then
if not ( ignored and ignored[k] ) then
local dv = default and default[k]
if type(v) == "table" then
local result = serialize(tbl[k], comp and comp[k], k, ignored, spacing .. " ")
if result then
match = true
str = str .. result
local sub = DiffConfig(v, type(dv) == "table" and dv or nil)
if sub then
diff = diff or {}
diff[k] = sub
end
elseif type(v) == "string" then
match = true
local escaped = string.gsub(v, "\\", "\\\\")
escaped = string.gsub(escaped, "\"", "\\\"")
str = str .. spacing .. " [\""..k.."\"] = \"".. escaped .."\",\n"
elseif type(v) == "number" then
match = true
str = str .. spacing .. " [\""..k.."\"] = ".. string.gsub(v, "\\", "\\\\") ..",\n"
elseif v ~= dv and ( type(v) == "string" or type(v) == "number" or type(v) == "boolean" ) then
diff = diff or {}
diff[k] = v
end
end
end
str = str .. spacing .. "}" .. ( spacing == "" and "" or "," ) .. "\n"
return match and str or nil
return diff
end
local function compress(input)
-- based on Rochet2's lzw compression
if type(input) ~= "string" then
return nil
-- EditBoxes don't soft-wrap one giant unbroken line; chunk the blob.
local function wrap(str, width)
local out = {}
for i = 1, strlen(str), width do
table.insert(out, strsub(str, i, i + width - 1))
end
local len = strlen(input)
if len <= 1 then
return "u"..input
end
local dict = {}
for i = 0, 255 do
local ic, iic = strchar(i), strchar(i, 0)
dict[ic] = iic
end
local a, b = 0, 1
local result = {"c"}
local resultlen = 1
local n = 2
local word = ""
for i = 1, len do
local c = strsub(input, i, i)
local wc = word..c
if not dict[wc] then
local write = dict[word]
if not write then
return nil
end
result[n] = write
resultlen = resultlen + strlen(write)
n = n+1
if len <= resultlen then
return "u"..input
end
local str = wc
if a >= 256 then
a, b = 0, b+1
if b >= 256 then
dict = {}
b = 1
end
end
dict[str] = strchar(a,b)
a = a+1
word = c
else
word = wc
end
end
result[n] = dict[word]
resultlen = resultlen+strlen(result[n])
n = n+1
if len <= resultlen then
return "u"..input
end
return table.concat(result)
return table.concat(out, "\n")
end
local function Encode(tbl)
return MAGIC .. wrap(C_EncodingUtil.EncodeBase64(
C_EncodingUtil.CompressString(
C_EncodingUtil.SerializeCBOR(tbl))), 92)
end
local function Decode(text)
if not text then return nil end
text = gsub(text, "%s", "")
if strsub(text, 1, strlen(MAGIC)) ~= MAGIC then return nil end
local ok, result = pcall(function()
return C_EncodingUtil.DeserializeCBOR(
C_EncodingUtil.DecompressString(
C_EncodingUtil.DecodeBase64(strsub(text, strlen(MAGIC) + 1))))
end)
if ok and type(result) == "table" then return result end
return nil
end
local function DecodeJSON(text)
if not text or gsub(text, "%s", "") == "" then return nil end
local ok, result = pcall(function()
return C_EncodingUtil.DeserializeJSON(text)
end)
if ok and type(result) == "table" then return result end
return nil
end
-- Legacy import (pre-!pf1! exports): base64 -> LZW -> Lua source
-- "pfUI_config = {...}". The base64 layer is standard and handled by
-- C_EncodingUtil.DecodeBase64; only the custom LZW format needs the old
-- Lua decoder. Import-only — new exports always use the CBOR pipeline.
local function decompress(input)
-- based on Rochet2's lzw compression
if type(input) ~= "string" or strlen(input) < 1 then
@@ -159,92 +144,32 @@ pfUI:RegisterModule("share", function ()
return table.concat(result)
end
local function enc(to_encode)
local index_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
local bit_pattern = ''
local encoded = ''
local trailing = ''
local function DecodeLegacy(text)
if not text or gsub(text, "%s", "") == "" then return nil end
for i = 1, string.len(to_encode) do
local remaining = tonumber(string.byte(string.sub(to_encode, i, i)))
local bin_bits = ''
for i = 7, 0, -1 do
local current_power = math.pow(2, i)
if remaining >= current_power then
bin_bits = bin_bits .. '1'
remaining = remaining - current_power
else
bin_bits = bin_bits .. '0'
end
end
bit_pattern = bit_pattern .. bin_bits
-- encoded blob? peel base64 + LZW down to Lua source. Raw (already
-- decoded) source pastes are accepted as-is.
local source = text
local stripped = gsub(text, "%s", "")
local ok, decoded = pcall(function()
return C_EncodingUtil.DecodeBase64(stripped)
end)
if ok and decoded then
local decompressed = decompress(decoded)
if decompressed then source = decompressed end
end
if mod(string.len(bit_pattern), 3) == 2 then
trailing = '=='
bit_pattern = bit_pattern .. '0000000000000000'
elseif mod(string.len(bit_pattern), 3) == 1 then
trailing = '='
bit_pattern = bit_pattern .. '00000000'
end
local chunk = loadstring(source)
if not chunk then return nil end
local count = 0
for i = 1, string.len(bit_pattern), 6 do
local byte = string.sub(bit_pattern, i, i+5)
local offset = tonumber(tonumber(byte, 2))
encoded = encoded .. string.sub(index_table, offset+1, offset+1)
count = count + 1
if count >= 92 then
encoded = encoded .. "\n"
count = 0
end
end
return string.sub(encoded, 1, -1 - string.len(trailing)) .. trailing
end
local function dec(to_decode)
local index_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
local padded = gsub(to_decode,"%s", "")
local unpadded = gsub(padded,"=", "")
local bit_pattern = ''
local decoded = ''
to_decode = gsub(to_decode,"\n", "")
to_decode = gsub(to_decode," ", "")
for i = 1, string.len(unpadded) do
local char = string.sub(to_decode, i, i)
local offset, _ = string.find(index_table, char)
if offset == nil then return nil end
local remaining = tonumber(offset-1)
local bin_bits = ''
for i = 7, 0, -1 do
local current_power = math.pow(2, i)
if remaining >= current_power then
bin_bits = bin_bits .. '1'
remaining = remaining - current_power
else
bin_bits = bin_bits .. '0'
end
end
bit_pattern = bit_pattern .. string.sub(bin_bits, 3)
end
for i = 1, string.len(bit_pattern), 8 do
local byte = string.sub(bit_pattern, i, i+7)
decoded = decoded .. strchar(tonumber(byte, 2))
end
local padding_length = string.len(padded)-string.len(unpadded)
if (padding_length == 1 or padding_length == 2) then
decoded = string.sub(decoded,1,-2)
end
return decoded
-- Sandbox the chunk: an empty environment means it can assign its
-- config table but can't reach any global or API function — a legacy
-- profile string is data, never code.
local sandbox = {}
setfenv(chunk, sandbox)
if not pcall(chunk) then return nil end
if type(sandbox.pfUI_config) == "table" then return sandbox.pfUI_config end
return nil
end
do -- Window
@@ -309,33 +234,43 @@ pfUI:RegisterModule("share", function ()
this:GetParent():UpdateScrollChildRect()
this:GetParent():UpdateScrollState()
local _, error = loadstring(f.scroll.text:GetText())
if error or string.gsub(this:GetText(), " ", "") == "" then
f.loadButton:Disable()
f.loadButton.text:SetTextColor(1,.5,.5,1)
else
local text = this:GetText()
local blob = Decode(text)
local json = not blob and DecodeJSON(text) or nil
local legacy = not blob and not json and DecodeLegacy(text) or nil
if blob or json or legacy then
f.loadButton:Enable()
f.loadButton.text:SetTextColor(.5,1,.5,1)
else
f.loadButton:Disable()
f.loadButton.text:SetTextColor(1,.5,.5,1)
end
local trydec = dec(this:GetText())
if string.gsub(this:GetText(), " ", "") == "" then
f.readButton.text:SetText(T["N/A"])
f.readButton:Disable()
elseif not trydec or trydec == "" then
f.readButton:Enable()
f.readButton.text:SetText(T["Encode"])
f.readButton.func = function()
local compressed = enc(compress(f.scroll.text:GetText()))
f.scroll.text:SetText(compressed)
end
else
if blob or legacy then
-- decoding a legacy string yields the JSON view; re-encoding it
-- from there produces a new-format blob (migration path)
f.readButton:Enable()
f.readButton.text:SetText(T["Decode"])
f.readButton.func = function()
local uncompressed = decompress(dec(f.scroll.text:GetText()))
f.scroll.text:SetText(uncompressed)
local current = f.scroll.text:GetText()
local config = Decode(current) or DecodeLegacy(current)
if config then
f.scroll.text:SetText(C_EncodingUtil.SerializeJSON(config))
end
end
elseif json then
f.readButton:Enable()
f.readButton.text:SetText(T["Encode"])
f.readButton.func = function()
local config = DecodeJSON(f.scroll.text:GetText())
if config then
f.scroll.text:SetText(Encode(config))
end
end
else
f.readButton:Disable()
f.readButton.text:SetText(T["N/A"])
end
end)
f.scroll:SetScrollChild(f.scroll.text)
@@ -387,21 +322,23 @@ pfUI:RegisterModule("share", function ()
f.loadButton.text:SetFont(pfUI.font_default, pfUI_config.global.font_size, "OUTLINE")
f.loadButton.text:SetText(T["Import"])
f.loadButton:SetScript("OnClick", function()
local ImportConfig, error = loadstring(f.scroll.text:GetText())
if not error and f.scroll.text:GetText() ~= "" then
ImportConfig()
pfUI:LoadConfig()
local text = f.scroll.text:GetText()
local config = Decode(text) or DecodeJSON(text) or DecodeLegacy(text)
if not config then return end
-- Skip firstrun wizard when importing a shared profile
-- The imported config is a complete setup, no wizard needed
if pfUI.firstrun and pfUI.firstrun.steps then
for _, step in pairs(pfUI.firstrun.steps) do
pfUI_init[step.name] = true
end
_G.pfUI_config = config
C = _G.pfUI_config
pfUI:LoadConfig()
-- Skip firstrun wizard when importing a shared profile
-- The imported config is a complete setup, no wizard needed
if pfUI.firstrun and pfUI.firstrun.steps then
for _, step in pairs(pfUI.firstrun.steps) do
pfUI_init[step.name] = true
end
CreateQuestionDialog(T["Some settings need to reload the UI to take effect.\nDo you want to reloadUI now?"], ReloadUI)
end
CreateQuestionDialog(T["Some settings need to reload the UI to take effect.\nDo you want to reloadUI now?"], ReloadUI)
end)
end
@@ -445,9 +382,9 @@ pfUI:RegisterModule("share", function ()
ignored["position"] = f.ignorePosition:GetChecked()
ignored["disabled"] = f.ignorePosition:GetChecked()
local compressed = enc(compress(serialize(myconfig, defconfig, "pfUI_config", ignored)))
f.scroll.text:SetText(compressed)
f.scroll.text.value = compressed
local encoded = Encode(DiffConfig(myconfig, defconfig, ignored) or {})
f.scroll.text:SetText(encoded)
f.scroll.text.value = encoded
f.scroll:SetVerticalScroll(0)
end)
end
@@ -457,4 +394,4 @@ pfUI:RegisterModule("share", function ()
f:Show()
end
end
end)
end)
+2 -2
View File
@@ -51,12 +51,12 @@ pfUI:RegisterModule("skin", function ()
DurabilityFrame.SetPoint = function() return end
if C.appearance.cd.blizzard == "1" then
hooksecurefunc("PaperDollItemSlotButton_Update", function()
pfUI.hooksecurefunc("PaperDollItemSlotButton_Update", function()
local cooldown = _G[this:GetName().."Cooldown"]
if cooldown then cooldown.pfCooldownType = "BLIZZARD" end
end)
hooksecurefunc("SpellButton_UpdateButton", function()
pfUI.hooksecurefunc("SpellButton_UpdateButton", function()
local cooldown = _G[this:GetName().."Cooldown"]
if cooldown then cooldown.pfCooldownType = "BLIZZARD" end
end)
+3 -3
View File
@@ -10,7 +10,7 @@ pfUI:RegisterModule("socialmod", function ()
end
end)
do -- add colors to guild list
hooksecurefunc("GuildStatus_Update", function()
pfUI.hooksecurefunc("GuildStatus_Update", function()
local playerzone = GetRealZoneText()
local off = FauxScrollFrame_GetOffset(GuildListScrollFrame)
for i=1, GUILDMEMBERS_TO_DISPLAY, 1 do
@@ -70,7 +70,7 @@ pfUI:RegisterModule("socialmod", function ()
end
do -- add colors to friend list
hooksecurefunc("FriendsList_Update", function()
pfUI.hooksecurefunc("FriendsList_Update", function()
if GetNumFriends() == 0 then return end
local playerzone = GetRealZoneText()
@@ -123,7 +123,7 @@ pfUI:RegisterModule("socialmod", function ()
end
do -- add colors to who list
hooksecurefunc("WhoList_Update", function()
pfUI.hooksecurefunc("WhoList_Update", function()
local num, max = GetNumWhoResults()
local off = FauxScrollFrame_GetOffset(WhoListScrollFrame)
+6 -8
View File
@@ -32,7 +32,6 @@ pfUI:RegisterModule("swingtimer", function ()
isDruid = false,
cachedHSSlots = {}, cachedCleaveSlots = {},
useSpellQueueEvent = false,
playerGUID = nil,
swingThrottle = 0,
onSwingCache = {},
}
@@ -789,7 +788,7 @@ pfUI:RegisterModule("swingtimer", function ()
events:RegisterEvent("AUTO_ATTACK_SELF")
events:RegisterEvent("AUTO_ATTACK_OTHER")
events:RegisterEvent("PLAYER_ENTERING_WORLD")
events:RegisterEvent("UNIT_INVENTORY_CHANGED")
events:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") -- ClassicAPI: per-slot, equipment-only
events:RegisterEvent("PLAYER_REGEN_DISABLED")
events:RegisterEvent("PLAYER_REGEN_ENABLED")
events:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
@@ -832,8 +831,7 @@ pfUI:RegisterModule("swingtimer", function ()
elseif event == "AUTO_ATTACK_OTHER" then
-- Parry haste: enemy attacked the player and player parried
local targetGuid = arg2
if not targetGuid or not S.playerGUID then return end
if targetGuid ~= S.playerGUID then return end
if not targetGuid or not IsPlayerGuid(targetGuid) then return end
local victimState = arg5 or 0
-- VICTIMSTATE_PARRY = 3
-- Vanilla: parry reduces the NEXT swing timer by 40% of weapon speed,
@@ -880,12 +878,12 @@ pfUI:RegisterModule("swingtimer", function ()
local _, class = UnitClass("player")
S.isWarrior = (class == "WARRIOR")
S.isDruid = (class == "DRUID")
S.playerGUID = UnitGUID("player")
UpdateWeaponSpeeds()
RebuildQueueSlotCache()
elseif event == "UNIT_INVENTORY_CHANGED" then
if arg1 and arg1 ~= "player" then return end
elseif event == "PLAYER_EQUIPMENT_CHANGED" then
-- arg1 = changed slot; only weapon slots (main/off/ranged) affect swing speed
if not INVSLOTS_EQUIPABLE_IN_COMBAT[arg1] then return end
UpdateWeaponSpeeds()
if S.ohSpeed == 0 then
S.ohActive = false
@@ -910,7 +908,7 @@ pfUI:RegisterModule("swingtimer", function ()
S.maulQueued = false
elseif event == "UNIT_DIED" then
if arg1 and arg1 == S.playerGUID then
if IsPlayerGuid(arg1) then
ResetAll()
end
end
+5 -5
View File
@@ -530,7 +530,7 @@ pfUI:RegisterModule("thirdparty-vanilla", function()
end
-- replace wim class colors with pfUI ones
hooksecurefunc("WIM_InitClassProps", function()
pfUI.hooksecurefunc("WIM_InitClassProps", function()
for class in pairs(PFUI_CLASS_COLORS) do
local wimclass = _G[format("WIM_LOCALIZED_%s",class)]
local colorstr = "|c" .. PFUI_CLASS_COLORS[class].colorStr
@@ -547,7 +547,7 @@ pfUI:RegisterModule("thirdparty-vanilla", function()
btnClose:SetWidth(13)
btnClose:SetHeight(13)
end
hooksecurefunc("WIM_Icon_DropDown_Update", function()
pfUI.hooksecurefunc("WIM_Icon_DropDown_Update", function()
for i=1,_G.WIM_MaxMenuCount do
local btn = _G["WIM_ConversationMenuTellButton"..i]
if i==1 and btn:IsEnabled() == 0 then return end
@@ -729,7 +729,7 @@ pfUI:RegisterModule("thirdparty-vanilla", function()
SkinScrollbar(WIM_HelpScrollFrameScrollBar)
end
hooksecurefunc("WIM_WindowOnShow", function()
pfUI.hooksecurefunc("WIM_WindowOnShow", function()
if this.backdrop then return end -- already skinned
local windowname = this:GetName()
@@ -904,7 +904,7 @@ pfUI:RegisterModule("thirdparty-vanilla", function()
end
-- trigger the event whenever SuperMacro got an update
hooksecurefunc("SM_UpdateActionSpell", function()
pfUI.hooksecurefunc("SM_UpdateActionSpell", function()
for slot=1,120 do pfUI.bars.update[slot] = true end
end)
end)
@@ -922,7 +922,7 @@ pfUI:RegisterModule("thirdparty-vanilla", function()
pfUI.bars.skip_macro = true
-- send clevermacro events to pfUI actionbars
hooksecurefunc("ActionButton_OnEvent", function(event)
pfUI.hooksecurefunc("ActionButton_OnEvent", function(event)
events(this, event)
end)
end)
+4 -62
View File
@@ -1,5 +1,5 @@
-- skip module initialization on every other client than turtle-wow
if not TargetHPText or not TargetHPPercText then return end
if not TURTLE_WOW_VERSION then return end
pfUI:RegisterModule("turtle-wow", function ()
-- Manage Turtle WoW's GroupUI (Turtle_GroupUI addon) vs pfUI frames.
@@ -65,14 +65,14 @@ pfUI:RegisterModule("turtle-wow", function ()
HookAddonOrVariable("GroupFrame", function()
-- After Turtle's own init, hide frames if pfUI handles them
hooksecurefunc("GroupFrame_Toggle", function()
pfUI.hooksecurefunc("GroupFrame_Toggle", function()
if pfUIHandlesGroupOrRaid() then
DisableTurtleGroupFrames()
end
end)
-- After every group/raid update, re-hide if pfUI handles them
hooksecurefunc("GroupFrame_Update", function()
pfUI.hooksecurefunc("GroupFrame_Update", function()
if pfUIHandlesGroupOrRaid() then
DisableTurtleGroupFrames()
end
@@ -86,64 +86,6 @@ pfUI:RegisterModule("turtle-wow", function ()
L["debuffs"]['Moonfire'] = {[1]=9.0,[2]=18.0,[3]=18.0,[4]=18.0,[5]=18.0,[6]=18.0,[7]=18.0,[8]=18.0,[9]=18.0,[10]=18.0,[0]=18.0}
L["debuffs"]['Deep Wound'] = {[0]=6.0}
-- add custom spell logic to libdebuff
HookScript(libdebuff, "OnEvent", function()
if event == "CHAT_MSG_SPELL_SELF_DAMAGE" then
-- refresh paladin judgements on holy strike
-- taken from: https://github.com/doorknob6/pfUI-turtle/blob/master/modules/debuffs.lua
local holystrike = string.find(string.sub(arg1,6,17), "Holy Strike")
--arg2 is spell dmg when it hits, nil when it misses
if holystrike and arg2 then
for seal in L["judgements"] do
local name = UnitName("target")
local level = UnitLevel("target")
if name and libdebuff.objects[name] then
if level and
libdebuff.objects[name][level] and
libdebuff.objects[name][level][seal] then
libdebuff:AddEffect(name, level, seal)
elseif libdebuff.objects[name][0] and
libdebuff.objects[name][0][seal] then
libdebuff:AddEffect(name, 0, seal)
end
end
end
end
-- refresh rip and rake duration on ferocious bite (Turtle WoW feature)
-- Only refresh if Ferocious Bite actually hit (not missed/dodged/parried/etc.)
local match = string.find(arg1, "Ferocious Bite")
if match and arg2 and not libdebuff:DidSpellFail("Ferocious Bite") then
local name = UnitName("target")
local level = UnitLevel("target")
-- Refresh Rip mit existierender Duration
if libdebuff.objects[name] and libdebuff.objects[name][level] and libdebuff.objects[name][level]["Rip"] then
local existingDuration = libdebuff.objects[name][level]["Rip"].duration
libdebuff:AddEffect(name, level, "Rip", existingDuration)
end
-- Refresh Rake mit existierender Duration
if libdebuff.objects[name] and libdebuff.objects[name][level] and libdebuff.objects[name][level]["Rake"] then
local existingDuration = libdebuff.objects[name][level]["Rake"].duration
libdebuff:AddEffect(name, level, "Rake", existingDuration)
end
end
-- refresh Immolate duration after cast Conflagrate
-- Only refresh if Conflagrate actually hit
local conflagrate = string.find(string.sub(arg1,6,17), "Conflagrate")
if conflagrate and arg2 and not libdebuff:DidSpellFail("Conflagrate") then
local name = UnitName("target")
local level = UnitLevel("target")
if libdebuff.objects[name] and libdebuff.objects[name][level] and libdebuff.objects[name][level]["Immolate"] then
local duration = libdebuff.objects[name][level]["Immolate"].duration
libdebuff:UpdateDuration(name, level, "Immolate", duration - 3)
end
end
end
end)
-- turtle wow totemic recall clear totem indicators
local _, class = UnitClass("player")
if libtotem and class == "SHAMAN" then
@@ -353,7 +295,7 @@ pfUI:RegisterModule("turtle-wow", function ()
local initialized = false
HookAddonOrVariable("Blizzard_InspectUI", function()
hooksecurefunc("InspectFrame_Show", function()
pfUI.hooksecurefunc("InspectFrame_Show", function()
-- break if theres nothing left to do
if initialized then return end
+2 -2
View File
@@ -41,12 +41,12 @@ pfUI:RegisterModule("unusable", function ()
end
-- update on regular pfUI button updates
hooksecurefunc(pfUI.bag, "UpdateSlot", function(self, bag, slot)
pfUI.hooksecurefunc(pfUI.bag, "UpdateSlot", function(self, bag, slot)
pfUI.unusable:UpdateSlot(bag, slot)
end)
-- update on bank frame itemlock updates
hooksecurefunc("BankFrameItemButton_UpdateLock", function()
pfUI.hooksecurefunc("BankFrameItemButton_UpdateLock", function()
pfUI.unusable:UpdateSlot(-1, this:GetID())
end)
end)
+1 -1
View File
@@ -5,7 +5,7 @@ pfUI:RegisterModule("xpbar", function ()
local REST_WINDOW = 300 -- seconds of sliding-window samples for rate calc
local REST_CAP_MUL = 1.5 -- target rested cap = UnitXPMax * 1.5
if IsTurtleWoW() then
if TURTLE_WOW_VERSION then
REST_CAP_MUL = 1.13
end
+1 -2
View File
@@ -27,7 +27,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 = 10507 -- (X*10000 + Y*100 + Z)
local PFUI_CLASSIC_API_MIN = 10511 -- (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"
@@ -99,7 +99,6 @@ pfUI.skins = {}
pfUI.environment = {}
pfUI.movables = {}
pfUI.version = {}
pfUI.hooks = {}
pfUI.env = {}
pfUI.events = Mixin({}, CallbackRegistryMixin)
+5 -5
View File
@@ -12,7 +12,7 @@ pfUI:RegisterSkin("Auctionhouse", function ()
SkinArrowButton(AuctionsNextPageButton, "right", 18)
end
hooksecurefunc("AuctionFrame_OnShow", function()
pfUI.hooksecurefunc("AuctionFrame_OnShow", function()
AuctionFrame:ClearAllPoints()
AuctionFrame:SetPoint("TOPLEFT", 10, -104)
end)
@@ -76,7 +76,7 @@ pfUI:RegisterSkin("Auctionhouse", function ()
item:SetPoint("LEFT", 2, 0)
end
end
hooksecurefunc("AuctionFrameBrowse_Update", function()
pfUI.hooksecurefunc("AuctionFrameBrowse_Update", function()
for i = 1, NUM_BROWSE_TO_DISPLAY do
HandleIcon(_G["BrowseButton"..i.."Item"], _G["BrowseButton"..i.."ItemIconTexture"])
end
@@ -145,7 +145,7 @@ pfUI:RegisterSkin("Auctionhouse", function ()
item:ClearAllPoints()
item:SetPoint("LEFT", 2, 0)
end
hooksecurefunc("AuctionFrameBid_Update", function()
pfUI.hooksecurefunc("AuctionFrameBid_Update", function()
for i = 1, NUM_BIDS_TO_DISPLAY do
HandleIcon(_G["BidButton"..i.."Item"], _G["BidButton"..i.."ItemIconTexture"])
end
@@ -191,14 +191,14 @@ pfUI:RegisterSkin("Auctionhouse", function ()
item:ClearAllPoints()
item:SetPoint("LEFT", 2, 0)
end
hooksecurefunc("AuctionFrameAuctions_Update", function()
pfUI.hooksecurefunc("AuctionFrameAuctions_Update", function()
for i = 1, NUM_AUCTIONS_TO_DISPLAY do
HandleIcon(_G["AuctionsButton"..i.."Item"], _G["AuctionsButton"..i.."ItemIconTexture"])
end
end)
SkinButton(AuctionsItemButton)
hooksecurefunc("AuctionSellItemButton_OnEvent", function()
pfUI.hooksecurefunc("AuctionSellItemButton_OnEvent", function()
if event ~= "NEW_AUCTION_UPDATE" then return end
HandleIcon(AuctionsItemButton, AuctionsItemButton:GetNormalTexture())
end)
+1 -1
View File
@@ -19,7 +19,7 @@ pfUI:RegisterSkin("Battlefield Minimap", function ()
BattlefieldMinimapTab:Hide()
end)
hooksecurefunc("BattlefieldMinimap_ShowOpacity", function()
pfUI.hooksecurefunc("BattlefieldMinimap_ShowOpacity", function()
OpacityFrame:ClearAllPoints()
OpacityFrame:SetPoint("TOPRIGHT", "BattlefieldMinimap", "TOPLEFT", -2*border, 0)
end)
+4 -4
View File
@@ -136,18 +136,18 @@ pfUI:RegisterSkin("Character", function ()
end
end
hooksecurefunc("CharacterFrame_OnShow", function()
pfUI.hooksecurefunc("CharacterFrame_OnShow", function()
RefreshCharacterSlots()
RefreshPetPosition()
end)
hooksecurefunc("PaperDollItemSlotButton_Update", function()
pfUI.hooksecurefunc("PaperDollItemSlotButton_Update", function()
if this:GetParent() == PaperDollFrame then
RefreshCharacterSlot(this)
end
end)
hooksecurefunc("PetTab_Update", RefreshPetPosition)
pfUI.hooksecurefunc("PetTab_Update", RefreshPetPosition)
StripTextures(PaperDollFrame)
StripTextures(CharacterAttributesFrame)
@@ -270,7 +270,7 @@ pfUI:RegisterSkin("Character", function ()
-- the FactionStanding text from `bar.standingText` on mouseout, so we
-- stash our augmented text there too — otherwise hovering a bar strips
-- the "(N)" suffix off.
hooksecurefunc("ReputationFrame_Update", function()
pfUI.hooksecurefunc("ReputationFrame_Update", function()
if C.character.reputation.repRequired ~= "1" then return end
local offset = FauxScrollFrame_GetOffset(ReputationListScrollFrame)
for i = 1, NUM_FACTIONS_DISPLAYED do
+2 -2
View File
@@ -150,7 +150,7 @@ pfUI:RegisterSkin("Friends", function ()
end
-- set positions
hooksecurefunc("WhoList_Update", function()
pfUI.hooksecurefunc("WhoList_Update", function()
for i = 1, WHOS_TO_DISPLAY do
local level = _G["WhoFrameButton"..i.."Level"]
level:ClearAllPoints()
@@ -231,7 +231,7 @@ pfUI:RegisterSkin("Friends", function ()
end
-- set positions
hooksecurefunc("GuildStatus_Update", function()
pfUI.hooksecurefunc("GuildStatus_Update", function()
for i = 1, GUILDMEMBERS_TO_DISPLAY do
local level = _G["GuildFrameButton"..i.."Level"]
level:ClearAllPoints()
+2 -2
View File
@@ -24,11 +24,11 @@ pfUI:RegisterSkin("Gossip and Quest", function ()
QuestRewardItemHighlightBG:SetTexture(1,1,1,.2)
QuestRewardItemHighlightBG:SetAllPoints()
hooksecurefunc("QuestFrameItems_Update", function()
pfUI.hooksecurefunc("QuestFrameItems_Update", function()
QuestRewardItemHighlight:Hide()
end)
hooksecurefunc("QuestRewardItem_OnClick", function()
pfUI.hooksecurefunc("QuestRewardItem_OnClick", function()
if this.type == "choice" then
QuestRewardItemHighlight:SetAllPoints(this.backdrop)
QuestRewardItemHighlight:Show()
+2 -2
View File
@@ -12,7 +12,7 @@ pfUI:RegisterSkin("Mailbox", function ()
StripTextures(SendMailPackageButton)
SkinButton(SendMailPackageButton, nil, nil, nil, nil, true)
hooksecurefunc("SendMailFrame_Update", function()
pfUI.hooksecurefunc("SendMailFrame_Update", function()
HandleIcon(SendMailPackageButton, SendMailPackageButton:GetNormalTexture())
local _, itemID = GetSendMailItemLink()
@@ -62,7 +62,7 @@ pfUI:RegisterSkin("Mailbox", function ()
do -- OpenMailFrame
SkinButton(OpenMailPackageButton, nil, nil, nil, OpenMailPackageButtonIconTexture)
hooksecurefunc("InboxFrame_OnClick", function(index)
pfUI.hooksecurefunc("InboxFrame_OnClick", function(index)
local _, itemID = GetInboxItemLink(index)
if itemID then
local quality = C_Item.GetItemQualityByID(itemID)
+2 -2
View File
@@ -6,7 +6,7 @@ pfUI:RegisterSkin("Merchant", function ()
if MerchantGuildBankRepairButton then -- tbc
SkinButton(MerchantGuildBankRepairButton, nil, nil, nil, MerchantGuildBankRepairButtonIcon)
MerchantGuildBankRepairButtonIcon:SetTexCoord(.59, .82, .06, .54)
hooksecurefunc("MerchantFrame_UpdateRepairButtons", function()
pfUI.hooksecurefunc("MerchantFrame_UpdateRepairButtons", function()
MerchantGuildBankRepairButton:ClearAllPoints()
MerchantGuildBankRepairButton:SetPoint("RIGHT", MerchantBuyBackItemItemButton, "LEFT", -14, 0)
MerchantRepairAllButton:ClearAllPoints()
@@ -56,7 +56,7 @@ pfUI:RegisterSkin("Merchant", function ()
moneyFrame:SetPoint("BOTTOMLEFT", itemButton, "BOTTOMRIGHT", 5, 1)
end
hooksecurefunc("MerchantFrame_UpdateMerchantInfo", function()
pfUI.hooksecurefunc("MerchantFrame_UpdateMerchantInfo", function()
if MerchantFrame.selectedTab == 1 then
for i = 3, 11, 2 do
_G["MerchantItem"..i]:ClearAllPoints()
+1 -1
View File
@@ -184,7 +184,7 @@ pfUI:RegisterSkin("Options - New", function ()
end
-- hook after category selection: UpdateOptions is local so we hook its caller
hooksecurefunc("OptionsListButton_OnClick", SkinControls)
pfUI.hooksecurefunc("OptionsListButton_OnClick", SkinControls)
-- also cover initial load
HookScript(OptionsFrame, "OnShow", SkinControls)
end)
+1 -1
View File
@@ -19,7 +19,7 @@ pfUI:RegisterSkin("Options - Video", function ()
slider:SetPoint(point, anchor, anchorPoint, x, y - shift)
end
hooksecurefunc("OptionsFrame_Load", function()
pfUI.hooksecurefunc("OptionsFrame_Load", function()
OptionsFramePixelShaders:SetWidth(230)
OptionsFrameMiscellaneous:ClearAllPoints()
OptionsFrameMiscellaneous:SetPoint("LEFT", OptionsFramePixelShaders, "RIGHT", 6, 0)
+1 -1
View File
@@ -192,7 +192,7 @@ pfUI:RegisterSkin("Profession", function ()
reagentlabel:SetTextColor(1,1,1,1)
local scanner = libtipscan:GetScanner(name)
hooksecurefunc(SetSelection, function(id)
pfUI.hooksecurefunc(SetSelection, function(id)
if id and id ~= 0 then
detailscroll:Show()
HandleIcon(icon, icon:GetNormalTexture())
+3 -3
View File
@@ -13,7 +13,7 @@ pfUI:RegisterSkin("Quest Log", function ()
StripTextures(QUEST_COUNT)
QUEST_COUNT:ClearAllPoints()
hooksecurefunc("QuestLogUpdateQuestCount", function(numQuests)
pfUI.hooksecurefunc("QuestLogUpdateQuestCount", function(numQuests)
QUEST_COUNT:ClearAllPoints()
QUEST_COUNT:SetPoint("BOTTOMRIGHT", QuestLogFrame, "TOPRIGHT", 0, -50)
end)
@@ -24,7 +24,7 @@ pfUI:RegisterSkin("Quest Log", function ()
QUEST_COUNT:SetPoint("TOPRIGHT", -10, -30)
end
hooksecurefunc("QuestLog_OnShow", function()
pfUI.hooksecurefunc("QuestLog_OnShow", function()
QuestLogFrame:ClearAllPoints()
QuestLogFrame:SetPoint("TOPLEFT", 10, -104)
end)
@@ -163,7 +163,7 @@ pfUI:RegisterSkin("Quest Log", function ()
QuestLogListScrollFrame:SetPoint("TOPLEFT", 10, -54)
QuestLogListScrollFrame:SetHeight(350)
hooksecurefunc("QuestLog_Update", function()
pfUI.hooksecurefunc("QuestLog_Update", function()
local numEntries = GetNumQuestLogEntries()
local questIndex, text, level, questTag, isHeader
+2 -2
View File
@@ -38,12 +38,12 @@ pfUI:RegisterSkin("Readycheck", function ()
frame.bar.text:SetPoint("CENTER", 0, 0)
local max
hooksecurefunc("ShowReadyCheck", function()
pfUI.hooksecurefunc("ShowReadyCheck", function()
max = ReadyCheckFrame.timer
frame.bar:SetMinMaxValues(0, max)
end)
hooksecurefunc(update_func, function()
pfUI.hooksecurefunc(update_func, function()
if not ReadyCheckFrame.timer then return end
local perc = ReadyCheckFrame.timer/max
+1 -1
View File
@@ -32,7 +32,7 @@ pfUI:RegisterSkin("GM Survey", function ()
CreateBackdrop(GMSurveyCommentFrame, nil, true, .75)
SkinScrollbar(GMSurveyCommentScrollFrameScrollBar)
GMSurveyFrameComment:SetMaxLetters(2000)
hooksecurefunc("GMSurveyFrame_Update", function()
pfUI.hooksecurefunc("GMSurveyFrame_Update", function()
GMSurveyFrameComment:SetWidth(505)
end)
end)
+1 -1
View File
@@ -41,7 +41,7 @@ pfUI:RegisterSkin("Trade", function ()
RecipientButtonBG:SetAllPoints()
end
hooksecurefunc("TradeFrame_UpdateTargetItem", function(id)
pfUI.hooksecurefunc("TradeFrame_UpdateTargetItem", function(id)
HandleIcon(_G["TradeRecipientItem"..id.."ItemButton"], _G["TradeRecipientItem"..id..'IconTexture'])
end)
+1 -1
View File
@@ -36,7 +36,7 @@ pfUI:RegisterSkin("Trainer", function ()
StripTextures(ClassTrainerSkillIcon)
SkinButton(ClassTrainerSkillIcon, nil, nil, nil, nil, true)
hooksecurefunc("ClassTrainer_SetSelection", function()
pfUI.hooksecurefunc("ClassTrainer_SetSelection", function()
HandleIcon(ClassTrainerSkillIcon, ClassTrainerSkillIcon:GetNormalTexture())
end)