A pfUI fork specifically optimized for Turtle WoW which requires SuperWoW and Nampower with optional UnitXP_SP3 DLL integration.
This version includes significant performance improvements, DLL-enhanced features, and TBC spell indicators that work with Turtle WoW's expanded spell library.
Looking for TBC support? Visit the original pfUI by Shagu: https://github.com/shagu/pfUI
Major performance rewrite: UnitDebuff() now runs entirely through Nampower's GetUnitField โ zero Blizzard API calls, zero tooltip scans.
Previously, every debuff icon required three expensive calls per update:
UnitDebuff(unit, slot)โ Blizzard C-side API callscanner:SetUnitDebuff(unit, slot)โ Tooltip object creation + GameTooltip parsescanner:Line(1)โ String extraction from tooltip
All three are now replaced by pure Lua table lookups into cached GetUnitField data:
| Data | Old (Blizzard API) | New (GetUnitField) |
|---|---|---|
| Spell Name | Tooltip scan | SpellInfo(spellId) |
| Texture | UnitDebuff() ret.1 |
GetSpellIconTexture(GetSpellRecField(spellId, "spellIconID")) |
| Stacks | UnitDebuff() ret.2 |
GetUnitField(guid, "auraApplications")[slot] |
| DebuffType | UnitDebuff() ret.3 |
GetSpellRecField(spellId, "dispel") โ dispelTypeMap |
| Duration/Timeleft | ownDebuffs tracking | unchanged |
| Caster | slotOwnership tracking | unchanged |
Performance impact: With 5 debuffs on target = 15 expensive calls eliminated per update cycle. With 10 visible nameplates ร 3 debuffs = 90 calls eliminated per refresh. Estimated 3-5x faster per UnitDebuff call.
DebuffType now works in Nampower path: Previously dtype was only available from Blizzard's UnitDebuff(). Now resolved from SpellRec DBC via GetSpellRecField(spellId, "dispel"), meaning debuff frame border colors (Magic=blue, Curse=purple, Poison=green, Disease=brown) now work correctly for all units including nameplates.
Castbar now shows the correct item icon and item name for item-triggered casts!
Previously, using items with cast times (Gnomish Death Ray, Net-o-Matic, Noggenfogger Elixir etc.) showed the generic spell icon and spell name on the castbar. Now:
- โ
SPELL_START_SELF/OTHERarg1(itemId) is now parsed and used - โ
SPELL_GO_SELF/OTHERarg1(itemId) is now parsed - โ
Item icon resolved via
GetItemStatsField(itemId, "displayInfoID")โGetItemIconTexture() - โ
Item name resolved via
GetItemStatsField(itemId, "displayName") - โ
pfUI.libdebuff_item_iconsโ Persistent item icon/name cache that survives SPELL_GO clearing cast data - โ
castbar.luaโ Reads item icon + name from persistent cache with fallback to spell data
Note: Item icon/name detection only works for your own casts (WoW 1.12.1 protocol limitation โ server sends itemId=0 to other clients).
Fixed missing icons from Nampower texture functions.
GetSpellIconTexture() and GetItemIconTexture() return short texture names (e.g. INV_Gizmo_08) without the Interface\Icons\ prefix required by SetTexture(). Both GetSpellIcon() and the item icon lookup now auto-prefix the full path when needed.
- โ
Carnage frame recycling โ Persistent
carnageCheckFramereused instead ofCreateFrame()per Ferocious Bite (eliminates frame leak in combat) - โ
Recycled cleanup buffers โ
_cleanupBuf1/_cleanupBuf2reused instead oftable.insert+ new table perCleanupExpiredTimerscall - โ
SelfOverwrite buffer recycling โ Reused buffer instead of new
oldCasterstable per overwrite - โ
Pre-defined sort function โ
_ownDebuffSortFuncdefined once instead of anonymous closure perUnitOwnDebuffcall - โ spellId stored in ownDebuffs โ Enables direct DBC lookups for dtype without slotMap iteration
libdebuff.lua:
- Blizzard API calls in Nampower path: 3 per debuff โ 0
- New GetUnitField calls:
aura+auraApplications(cached 50ms) - New DBC lookups:
GetSpellRecField(spellId, "dispel")for dtype - New exports:
pfUI.libdebuff_item_icons
castbar.lua:
- Item icon override via
pfUI.libdebuff_item_icons(persistent cache) - Item name override via
GetItemStatsField(itemId, "displayName") - Works for player + target + focus castbars
- Added a new menu in /pfui named "Throttling" - Players who were unsatisfied with the throttling update rate can change it now for nameplates, Toolip Cursor and Chat Tab.
Major architectural change: Cast tracking moved from nameplates to libdebuff for single source of truth!
Previously, both nameplates.lua and libdebuff.lua independently tracked cast events, creating code duplication and maintenance overhead. Now all cast tracking is centralized in libdebuff.lua with nameplates consuming shared data.
libdebuff.lua - NEW Cast Tracking:
- โ
SPELL_START_SELF/OTHERโ Cast-Start Tracking - โ
SPELL_GO_SELF/OTHERโ Cast-Completion Tracking - โ
SPELL_FAILED_OTHERโ Cast-Cancel Detection (movement, interrupts, OOM) - โ
pfUI.libdebuff_castsโ Shared cast data structure[casterGuid] = {spellID, spellName, icon, startTime, duration, endTime, event} - โ
pfUI.libdebuff_GetSpellIcon()โ Icon cache export function
nameplates.lua - Simplified Cast Consumption:
- โ
GetCastInfo(guid)โ ReadspfUI.libdebuff_casts - โ
pfUI.libdebuff_GetSpellIconโ Uses shared icon cache - โ
UNIT_CASTEVENTโ REMOVED (replaced by Nampower SPELL_* events) - โ Local cast tracking code โ REMOVED (~56 lines saved)
Benefits:
- 100% Nampower, 0% SuperWOW - No longer depends on UNIT_CASTEVENT
- Single Source of Truth - Cast data only tracked once
- Icon Cache 100-400x faster - First lookup via Nampower's GetSpellIconTexture, then cached
- Easier Maintenance - Changes only in one place
- Code Reduction - 56 lines removed from nameplates.lua
Now requires Nampower 2.27.2+ (SPELL_FAILED_OTHER bug fix):
Version 2.27.1 had a bug where SPELL_FAILED_OTHER didn't fire for movement-cancelled casts. This is now fixed in 2.27.2.
User Warnings:
- 2.27.2+: โ Success message + auto-enable CVars
- 2.27.1:
โ ๏ธ Yellow warning + popup (cast-bar cancel broken) - < 2.27.1: โ Red error + popup (debuff tracking disabled)
- No Nampower: โ Red error + popup (addon disabled)
NEW StaticPopup Dialogs:
Popups appear center-screen on login to ensure users don't miss the version requirement!
Major enhancement: libdebuff integration for server-accurate HoT tracking!
Previously, libpredict relied purely on prediction (UNIT_CASTEVENT + timing calculations). Now it uses libdebuff's AURA_CAST events for server-side accurate buff/debuff data when available.
NEW Hybrid System:
GetHotDuration(unit, spell):
1. Try libdebuff first (Nampower AURA_CAST events)
โ
if available: return server-accurate data
2. Fallback to prediction (legacy system)
โ
Use hots[] table with UNIT_CASTEVENT prediction
Benefits:
- โ Server-accurate durations - No prediction needed with Nampower
- โ Automatic rank protection - Built into libdebuff's system
- โ Multi-caster support - Multiple druids = multiple rejuvs tracked separately
- โ Zero overhead - libdebuff already tracks all auras
- โ Backwards compatible - Falls back to prediction without Nampower
NEW Rank Support for HoTs:
Extended Hot() function signature to include rank parameter:
function libpredict:Hot(sender, target, spell, duration, startTime, source, rank)Rank Protection Logic:
- Don't overwrite Rank 10 HoT with Rank 8!
- Active higher-rank HoTs block lower-rank applications
- Works with multiple casters simultaneously
HealComm Protocol Extended (Backwards Compatible):
- OLD:
"Reju/TargetName/15/" - NEW:
"Reju/TargetName/15/10/"(rank added) "0"= unknown rank (for non-rank-aware clients)
Example Scenario:
Druid A casts Rejuvenation Rank 10 (15s duration)
Druid B casts Rejuvenation Rank 8 (12s duration)
With rank protection:
โ Rank 8 is BLOCKED while Rank 10 is active!
โ No more accidental overwrites of better HoTs!
libdebuff.lua:
- Lines: 2743 โ 2835 (+92 lines)
- Events: 12 โ 15 (+3: SPELL_START_SELF/OTHER, SPELL_FAILED_OTHER)
- Exports: 14 โ 16 (+2: pfUI.libdebuff_casts, pfUI.libdebuff_GetSpellIcon)
nameplates.lua:
- Lines: 1826 โ 1770 (-56 lines)
- Events: 7 โ 6 (-1: UNIT_CASTEVENT removed)
- Code removed: ~74 lines (UNIT_CASTEVENT handler, local cast tracking)
libpredict.lua:
- Lines: 935 โ 1095 (+160 lines)
- New: libdebuff integration, rank support, rank protection logic
- Backwards compatible: Works with/without Nampower
-
Added icon cache system - Icons are now cached in pfUI.libdebuff_icon_cache for instant lookups after first access
-
Replaced SpellInfo texture lookups with GetSpellIconTexture - Direct DBC queries via Nampower (~100-400x faster than tooltip parsing)
-
Optimized UnitDebuff() function - Now uses GetUnitField("aura") to retrieve spell IDs directly from unit data, then fetches icons via GetSpellIconTexture instead of vanilla UnitDebuff API
-
Changed fallback icons - Unknown spell icons now display QuestionMark instead of class-specific icons
-
Performance impact - Icon lookups reduced from ~5-20ms to ~0.05ms (first) / ~0.001ms (cached) per debuff, resulting in 600-2600x speedup for full debuff bars
-
Replaced in libdebuff.lua the UNIT_CASTEVENT of Superwow with Nampowers SPELL_GO and SPELL_START events (slowly trying to get away from superwow, not maintained anymore and outdated)
Fixed buff timers resetting on Player Buff/Debuff Bars when other buffs expire:
Previously, buff bar timers would reset or jump when other buffs expired because the UUID (unique identifier) included the slot number. Since slots shift when buffs expire, the same buff would get a new UUID, causing the timer bar to think it's a new buff.
The Problem:
- Old UUID:
texture + name + slot(e.g., "PowerWordFortitude_tex_PWF_3") - Buff in slot 3 expires โ slots 4,5,6 shift down to 3,4,5
- UUID changes from
..._4to..._3โ timer resets!
The Solution:
- Player buffs now use:
texture + nameonly (no slot) - Target debuffs still use:
texture + name + slot(needed for multi-caster scenarios)
-- For player: no slot in uuid (slots shift when other buffs expire)
-- For target: include slot (multiple players can have same debuff)
local uuid
if frame.unit == "player" then
uuid = data[4] .. data[3] -- texture + name only
else
uuid = data[4] .. data[3] .. data[2] -- texture + name + slot
endNo more phantom timers for immune targets:
When a target is immune to your debuff (e.g., Rake bleed on a bleed-immune mob), the AURA_CAST event fires but DEBUFF_ADDED never comes. Previously this could create a timer with icon for a debuff that was never actually applied.
The Fix:
- Debuff data now requires
slotto be set (confirmed byDEBUFF_ADDED_OTHERevent) - If
AURA_CASTfires butDEBUFF_ADDEDnever comes โslotstaysnilโ no timer/icon shown
-- IMMUNITY CHECK: Only show if slot is set (confirmed by DEBUFF_ADDED_OTHER)
-- This prevents showing timers for spells like Rake where the bleed is immune
if data.slot and timeleft > -1 then
-- Show the debuff
endEnhanced UnitDebuff() API - 8th return value is now caster:
local name, rank, texture, stacks, dtype, duration, timeleft, caster = libdebuff:UnitDebuff(unit, id)
-- caster = "player" (your debuff), "other" (someone else's), or nil (unknown)Use Cases:
- Buff bar tooltip can now find correct slot for "only own debuffs" mode
- UI can differentiate between your debuffs and others' debuffs
- Enables future features like "show only my debuffs" filters
Fixed tooltip showing wrong debuff in "only own debuffs" mode:
When using the "Show only own debuffs" option on Target Debuff Bars, hovering over a debuff could show the wrong tooltip because the displayed slot didn't match the actual game slot. Now searches through all game slots to find the correct one by matching spell name AND caster.
Fixed addon failing to load due to Lua 5.0's 32 local variable limit:
Lua 5.0 (used by WoW 1.12) has a hard limit of 32 local variables per function scope. As libdebuff grew, it hit this limit and stopped loading entirely.
The Solution: Moved 11 tables from local scope to pfUI. namespace:
| Old (local) | New (pfUI. namespace) |
|---|---|
ownDebuffs |
pfUI.libdebuff_own |
ownSlots |
pfUI.libdebuff_own_slots |
allSlots |
pfUI.libdebuff_all_slots |
allAuraCasts |
pfUI.libdebuff_all_auras |
pendingCasts |
pfUI.libdebuff_pending |
objectsByGuid |
pfUI.libdebuff_objects_guid |
debugStats |
pfUI.libdebuff_debugstats |
lastCastRanks |
pfUI.libdebuff_lastranks |
lastFailedSpells |
pfUI.libdebuff_lastfailed |
lastUnitDebuffLog |
pfUI.libdebuff_lastlog |
cache |
pfUI.libdebuff_cache |
Fixed client crash (Error 132) when logging out:
WoW crashes with Error 132 when addons make API calls like UnitExists() during shutdown, especially with UnitXP DLL installed.
The Fix: Register PLAYER_LOGOUT event and immediately disable all event handling:
frame:RegisterEvent("PLAYER_LOGOUT")
frame:SetScript("OnEvent", function()
if event == "PLAYER_LOGOUT" then
this:UnregisterAllEvents()
this:SetScript("OnEvent", nil)
return
end
-- ... rest of event handling
end)Applied to:
libdebuff.lua- All event framesnameplates.lua- nameplates + nameplates.combat framesnampower.lua- Spell queue indicator framesuperwow.lua- Secondary mana bar framesactionbar.lua- Page switch frame
Various small performance improvements across the codebase:
| Optimization | Location | Benefit |
|---|---|---|
childs table reuse |
nameplates.lua | Avoids creating new table every scan cycle |
Indexed access instead of pairs() |
nameplates.lua | Faster debuff timeout scanning |
| Quick exit if not in combat | nameplates.lua | Skips threatcolor calculation when unnecessary |
| Player GUID caching | libdebuff.lua | Avoids repeated UnitExists("player") calls |
| Consistent DoNothing() pattern | unitframes.lua, nameplates.lua | Lightweight frames when animation disabled |
For reference, here's everything the enhanced libdebuff system now provides:
Debuff Detection:
- โ Checks for dodges, misses, resists, parries, immunes, reflects, and evades
- โ Immunity check - no timer if debuff wasn't actually applied
- โ Tracks if debuff is from YOU or from OTHERS (including their GUID)
Rank & Duration:
- โ Rank protection - lower rank spells can't refresh higher rank timers
- โ
Shared debuff logic (
uniqueDebuffsanddebuffOverwritePairs) - โ Faerie Fire โ Faerie Fire (Feral), Demo Shout โ Demo Roar overwrites (with rank check!)
- โ Combo point finisher duration (Rip, Rupture, Kidney Shot)
- โ Talent-based duration modifiers (Booming Voice, Improved SW:P, etc.)
Tracking:
- โ Multi-target debuff tracking via GUID
- โ Debuff stack tracking for stackable debuffs
- โ Handles dispels and removals via events
API:
- โ
UnitDebuff()returns: name, rank, texture, stacks, dtype, duration, timeleft, caster - โ
UnitOwnDebuff()for filtering only your own debuffs - โ
Cleveroids API compatibility via
objectsByGuid
Debug Commands:
/shifttest start/stop/stats/slots- Debug debuff slot tracking/memcheck- Show memory usage statistics
Revolutionary frame creation system that eliminates unnecessary Model frames:
Previously, pfUI created expensive Model frames for every single buff/debuff cooldown timer, even when the animation was disabled. This caused significant performance overhead, especially in 40-man raids where hundreds of frames were created but never actually used.
The Problem:
- Old system: ALWAYS created Model frames with
CooldownFrameTemplate - When animation was disabled, frames were just hidden with
SetAlpha(0) - The frames still existed and consumed CPU resources in the background
- In raids: 40 players ร 32 buffs/debuffs = 1,280 Model frames running even when animations were off!
The Solution (Nameplates.lua + Unitframes.lua):
- New system: Creates Frame type based on config setting
- Animation ON โ Model frame with
CooldownFrameTemplate(expensive but animated) - Animation OFF โ Regular Frame with dummy functions (lightweight, no animation)
- Dummy functions (
DoNothing()) prevent crashes whenCooldownFrame_SetTimer()is called
Performance Impact:
| Scenario | Before 7.4.3 | After 7.4.3 | Improvement |
|---|---|---|---|
| Player frame (animation ON) | 32 Model frames | 32 Model frames | No change โ |
| 40 raid frames (animation OFF) | 1,280 Model frames | 1,280 Light frames | 100% lighter! ๐ |
| Mixed (player ON, raid OFF) | 1,312 Model frames | 32 Model + 1,280 Light | 98% less Model frames! ๐ฏ |
Real-World Example:
Before: ALL frames = 1,312 expensive Model frames
After: 32 Model (player) + 1,280 Light (raid) = 98% reduction in overhead
Technical Implementation:
-- Nameplates.lua & Unitframes.lua
if cooldown_anim == 1 then
-- Create expensive Model frame
cd = CreateFrame("Model", ...)
else
-- Create lightweight Frame
cd = CreateFrame("Frame", ...)
cd.AdvanceTime = DoNothing
cd.SetSequence = DoNothing
cd.SetSequenceTime = DoNothing
endUser Experience:
- โ
GUI Integration: Toggling "Show Timer Animation" now prompts for
/reload - โ Per-Frame Control: Each unitframe type (player/target/raid/party) has independent settings
- โ Immediate Effect: Reload applies the correct frame type based on your config
- โ No Visual Change: When animation is ON, everything looks identical (just way more efficient!)
Why This Matters:
- 40-man raids: Dramatically reduced frame update overhead
- Low-end PCs: Smoother gameplay with animations disabled
- Battery life: Less CPU usage = longer laptop battery
- Future-proof: Foundation for more performance optimizations
Compatibility:
- Works with existing timer text display (independent of animation)
- Fully backward compatible with all existing configs
- No changes needed to user settings (automatic on reload)
- Much faster debuff tracking - No more lag in 40-man raids
- 10x less memory usage - Runs cleaner over long raid sessions
- Instant cleanup - Dead mobs cleaned up immediately (was: 2-5 minutes)
- Multi-player debuffs - See debuffs from all raid members with accurate timers
- Rank protection - Lower rank spells can't overwrite higher ranks anymore
- 100% accurate positioning - Debuff icons always in the correct slot
- Better combo points - Rip, Rupture, Kidney Shot show correct duration
- โ
New Option: Enable Debuff Timers - Toggle for debuff timer display on nameplates
- Moved from hidden location (Appearance โ Cooldown โ "Display Debuff Durations") to Nameplates โ Debuffs
- All timer-related options are now grouped together for better discoverability
- โ
New Option: Show Timer Text - Toggle the countdown text (e.g., "12s") on debuff icons
- Previously always shown, now configurable
- โ Show Timer Animation - Existing pie-chart animation option, now properly grouped with other timer options
- โ
Live Config Updates - "Show Timer Animation" and "Show Timer Text" now update immediately
- Previously: Changes only applied after buffs/debuffs were refreshed
- Now: Toggling the option instantly shows/hides the animation and text on existing buffs/debuffs
- โ
DEBUFF_REMOVED now uses slotData.spellName - Previously used spellName from scan, which could be wrong after slot shifting
- When debuffs shift slots (e.g., slot 3 removed, slots 4+ shift down), the scan might read a different spell
- Now uses
removedSpellName = slotData.spellNamefrom stored slot data for consistency
- โ Cleanup empty spell tables - After removing a caster from allAuraCasts, checks if no other casters remain and removes the empty spell table
- โ Defensive casterGuid validation - Checks for empty string and "0x0000000000000000" before looking up timer data
- โ Invalid timer detection - Warns when remaining > duration (impossible state)
- โ ValidateSlotConsistency function - Debug function to verify allSlots and allAuraCasts consistency after shifting
- โ Enhanced debug logging - All debug messages now include target= for easier filtering
PLAYER_COMBO_POINTS event now works for Rogues:
The combo point tracking was previously only enabled for Druids. Rogues were completely ignored, causing abilities like Kidney Shot to always show base duration (1 sec) instead of the correct CP-scaled duration.
Technical Details:
- Nampower sends
durationMs=1000(base duration) for Kidney Shot - Code checked
if duration == 0before callingGetDuration() - Since duration was 1 (not 0), the CP calculation was skipped
- Fix: Always call
GetDuration()for CP-based abilities, regardless of event duration
Abbreviate Numbers (Settings โ General):
| Option | Example |
|---|---|
| Full Numbers | 4250 |
| 2 Decimals | 4.25k |
| 1 Decimal | 4.2k (always rounds DOWN) |
Castbar Timer Decimals (Settings โ General):
| Option | Example |
|---|---|
| 1 Decimal | 2.1 |
| 2 Decimals | 2.14 |
Smooth Castbar Animation:
- Fixed stuttering castbar caused by incorrect throttle placement
- Scanner throttle (0.05s) now only affects nameplate detection
- Castbar updates run at full 50 FPS for smooth animation
Countdown Timer:
- Castbar timer now counts DOWN (3.0 โ 0.0) instead of up
- Shows remaining cast time, not elapsed time
Intelligent Throttling (unchanged):
- Target OR casting nameplates: 0.02s (50 FPS)
- All other nameplates: 0.1s (10 FPS)
- Event updates bypass throttle entirely
Cache cleanup for hidden nameplates:
guidRegistrycleared when plate hidesCastEventscleared when plate hidesdebuffCachecleared when plate hidesthreatMemorycleared when plate hides
Prevents memory leaks when mobs die or go out of range.
Complete rewrite of health/mana lookups using Nampower's GetUnitField API:
The unitframes now use direct memory access via GetUnitField(guid, "health") instead of the slower UnitHealth() API calls. This provides significant performance improvements especially in raids.
Key Changes:
| Component | Before (7.2.0) | After (7.3.0) |
|---|---|---|
| HealPredict Health | UnitHealth() API calls |
GetUnitField(guid, "health") O(1) |
| Health Bar Colors | 4x redundant API calls per update | Uses cached hp_orig/hpmax_orig values |
| GetColor Function | UnitHealth() API calls |
GetUnitField(guid, "health") O(1) |
Fallback Support:
- Automatic fallback to
UnitHealth()when Nampower not available - Automatic fallback for units >180 yards (out of Nampower range)
- Automatic fallback when GUID unavailable
GUID-based tracking eliminates screen freezes when swapping raid groups:
Previously, any raid roster change would trigger a full update of ALL 40 raid frames, causing noticeable freezes. Now, only frames where the actual player changed get updated.
How it works:
-- OLD: RAID_ROSTER_UPDATE โ ALL 40 frames update_full = true โ FREEZE
-- NEW: RAID_ROSTER_UPDATE โ Check GUID per frame โ Only changed frames update| Scenario | Before (7.2.0) | After (7.3.0) |
|---|---|---|
| Swap 2 players | 40 frame updates | 2 frame updates |
| Player joins | 40 frame updates | 1 frame update |
| Player leaves | 40 frame updates | 1 frame update |
| No changes | 40 frame updates | 0 frame updates |
Technical Implementation:
pfUI.uf.guidTrackertracks GUID per frame- On roster change, compares old GUID vs new GUID
- Only sets
update_full = trueif GUID actually changed - Also forces
update_aura = trueto refresh buffs/debuffs
Eliminated redundant UnitName() calls:
UnitGetIncomingHeals(): Removed doubleUnitName()callUnitHasIncomingResurrection(): Removed doubleUnitName()callUNIT_HEALTHevent handler: Reuses cached name variable
Complete rewrite using Nampower's GetUnitField API:
The Druid Mana Bar feature (showing base mana while in shapeshift form) has been completely rewritten to use Nampower's native GetUnitField instead of the deprecated UnitMana() extended return values.
Key Changes:
| Component | Before (7.1.0) | After (7.2.0) |
|---|---|---|
| Data Source | UnitMana() second return value |
GetUnitField(guid, "power1") |
| Player Support | โ Druids only | โ Druids only |
| Target Support | โ Limited/broken | โ All classes can see Druid mana in all forms |
| Text Settings | Hardcoded format | Respects Power Bar text config |
New Features:
- โ Target Secondary Mana: See enemy/friendly Druid's base mana while they're in Cat/Bear form
- โ
Respects Power Text Settings: Uses same format as your Power Bar configuration (
powerdyn,power,powerperc,none, etc.) - โ Available for ALL Classes: Any class can now see Druid mana bars (controlled by "Show Druid Mana Bar" setting)
Technical Implementation:
-- OLD: Extended UnitMana (unreliable for other units)
local _, baseMana = UnitMana("target") -- Often returns nil for non-player
-- NEW: Direct field access via Nampower
local _, guid = UnitExists("target")
local baseMana = GetUnitField(guid, "power1") -- Base mana
local baseMaxMana = GetUnitField(guid, "maxPower1") -- Max base manasuperwow.lua:
- โ Removed legacy
pfDruidManabar (old SuperWoW-style implementation) - โ Removed
UnitMana()fallback code - โ
Unified all secondary mana bars to use
GetUnitField - โ
Fixed text centering issue (was using
SetJustifyH("RIGHT"))
nampower.lua - Massive Cleanup:
Removed significant amounts of dead/unused code:
| Removed Feature | Reason |
|---|---|
| Buff tracking system | Data collected but never displayed |
| HoT Detection (AURA_CAST events) | OnHotApplied callback never implemented |
Swing Timer (GetSwingTimers()) |
Never called anywhere in codebase |
| UNIT_DIED buff/debuff cleanup | Now handled by libdebuff |
Result: Cleaner, more maintainable code with reduced memory footprint.
Nameplate Debuff Animations:
- โ Added "Show Timer Animation" option for nameplate debuffs
- โ
Uses proper
Modelframe withCooldownFrameTemplatefor Vanilla client - โ Pie/swipe animation now works on nameplate debuff icons
- โ Configurable via GUI: Nameplates โ Show Timer Animation
Target Frame Debuff Animations:
- โ Timer animations now properly visible on target/player frame debuffs
- โ Fixed CD frame scaling and positioning for correct display
- โ
SetScale(size/32),SetAllPoints(),SetFrameLevel(14)for proper rendering
cooldown.lua Fix:
- โ
Added
elseif pfCooldownStyleAnimation == 1 then SetAlpha(1)to make animations visible - โ Previously animations were created but never shown (alpha stayed 0)
libdebuff.lua:
- โ
lastCastRankstable now cleaned up (entries older than 3 seconds removed) - โ
lastFailedSpellstable now cleaned up (entries older than 2 seconds removed) - โ Previously these tables grew indefinitely over long play sessions
unitframes.lua:
- โ
Cache cleanup now uses in-place
= nilinstead of creating new table every 30 seconds - โ Reduces garbage collector pressure
nameplates.lua:
- โ
Reusable
debuffSeentable instead of creatinglocal seen = {}on every DEBUFF_UPDATE event - โ Significant reduction in table allocations during combat
Event-Driven Architecture:
Replaced tooltip scanning with a pure event-based system using Nampower/SuperWoW:
OLD (Master):
-- Every UI update:
for slot = 1, 16 do
scanner:SetUnitDebuff("target", slot) -- Tooltip scan
local name = scanner:Line(1)
endNEW (Experiment):
-- Events fire when changes happen:
RegisterEvent("AURA_CAST_ON_SELF") -- You cast a debuff
RegisterEvent("DEBUFF_ADDED_OTHER") -- Debuff lands in slot
RegisterEvent("DEBUFF_REMOVED_OTHER") -- Debuff removed
-- UI reads from pre-computed tables:
local data = ownDebuffs[guid][spell] -- Direct lookupDynamic Duration Calculation:
| Ability | Formula | Durations (1-5 CP) |
|---|---|---|
| Rip | 8s + CP ร 2s | 10s / 12s / 14s / 16s / 18s |
| Rupture | 10s + CP ร 2s | 12s / 14s / 16s / 18s / 20s |
| Kidney Shot | 2s + CP ร 1s | 3s / 4s / 5s / 6s / 7s |
Before: All Rips showed 18s (wrong for 1-4 CP) After: Shows actual duration based on combo points used
Ferocious Bite Refresh Mechanics:
- Tracks Carnage talent (Rank 2) which makes Ferocious Bite refresh Rip & Rake
- Only refreshes when Ferocious Bite HITS (not on miss/dodge/parry)
- Preserves original duration (doesn't reset to new CP count)
- Uses
DidSpellFail()API for miss detection
- Debuff Overwrite Pairs: Faerie Fire โ Faerie Fire (Feral), Demoralizing Shout โ Demoralizing Roar
- Slot Shifting Algorithm: Accurate icon placement when debuffs expire
- Multi-Caster Tracking: Multiple players' debuffs tracked separately
- Rank Protection: Lower rank can't overwrite higher rank timer
- Unique Debuff System: Hunter's Mark, Scorpid Sting, etc. handled correctly
Master uses Blizzard API + Tooltip Scanning:
-- Every UnitDebuff call requires tooltip scan
function libdebuff:UnitDebuff(unit, id)
local texture, stacks, dtype = UnitDebuff(unit, id)
if texture then
scanner:SetUnitDebuff(unit, id) -- Tooltip scan to get spell name
effect = scanner:Line(1)
end
-- Duration comes from hardcoded lookup tables
end
-- UnitOwnDebuff iterates all 16 slots
function libdebuff:UnitOwnDebuff(unit, id)
for i = 1, 16 do
local effect = libdebuff:UnitDebuff(unit, i) -- 16 tooltip scans!
if caster == "player" then ...
end
endExperiment uses Nampower Events + GetUnitField:
-- Single call returns ALL 48 aura slots (32 buffs + 16 debuffs)
local auras = GetUnitField(guid, "aura") -- Returns array[48] of spell IDs
local stacks = GetUnitField(guid, "auraApplications") -- Returns array[48] of stack counts
-- Events fire with full data including duration
-- AURA_CAST_ON_OTHER: spellId, casterGuid, targetGuid, effect, effectAuraName,
-- effectAmplitude, effectMiscValue, durationMs, auraCapStatus
-- BUFF_REMOVED_OTHER: guid, slot, spellId, stackCount, auraLevel
-- UnitOwnDebuff is just a table lookup
function libdebuff:UnitOwnDebuff(unit, id)
local _, guid = UnitExists(unit)
local data = ownDebuffs[guid][spellName] -- Pre-computed by events
return data.duration, data.timeleft, ...
end| Feature | Purpose | Data Provided |
|---|---|---|
GetUnitField(guid, "aura") |
Single call returns all 48 aura spell IDs | array[48] of spell IDs |
GetUnitField(guid, "auraApplications") |
Stack counts for all auras | array[48] of stack counts |
GetUnitField(guid, "power1") |
Base mana for shapeshifted Druids | Mana value (7.2.0) |
GetUnitField(guid, "maxPower1") |
Max base mana | Max mana value (7.2.0) |
AURA_CAST_ON_OTHER |
Instant debuff cast detection | spellId, casterGuid, targetGuid, durationMs |
AURA_CAST_ON_SELF |
Instant self-buff detection | Same as above |
BUFF_REMOVED_OTHER |
Instant aura removal detection | guid, slot, spellId, stackCount |
DEBUFF_ADDED_OTHER |
Debuff slot assignment | guid, slot, spellId, stacks |
DEBUFF_REMOVED_OTHER |
Debuff removal with slot info | guid, slot, spellId |
Master uses none of these - it relies on:
UnitDebuff()API (no caster info, no duration)- Tooltip scanning via
GameTooltip:SetUnitDebuff()to get spell names - Chat message parsing (
CHAT_MSG_SPELL_PERIODIC_*) for duration detection - Hardcoded duration lookup tables
| Operation | Master | Experiment | Improvement |
|---|---|---|---|
| Initial target scan | 16 tooltip scans | 1 GetUnitField call (48 slots) | 16x fewer calls |
| Get YOUR debuffs | Loop 16 slots + tooltip each | Direct table lookup | ~50-100x faster |
| Debuff duration | Hardcoded tables / chat parsing | Event provides durationMs |
Accurate to ms |
| Detect debuff removal | Polling / timeout | BUFF_REMOVED_OTHER event |
Instant |
| Detect new debuff | Chat message delay | AURA_CAST_ON_OTHER event |
Instant |
| Caster identification | Not available | Event provides casterGuid |
New capability |
| Druid mana (other units) | Not available | GetUnitField(guid, "power1") |
New in 7.2.0 |
| Memory usage | ~50KB | ~200KB | 4x more (negligible) |
| Table | Before 7.1.0 | After 7.1.0 |
|---|---|---|
lastCastRanks |
Grew indefinitely | Cleaned every 30s (>3s old) |
lastFailedSpells |
Grew indefinitely | Cleaned every 30s (>2s old) |
debuffSeen (nameplates) |
New table per DEBUFF_UPDATE | Reused single table |
cleanedCache (unitframes) |
New table every 30s | In-place cleanup |
| File | Location | Changes |
|---|---|---|
buffwatch.lua |
modules/ |
Player buff bar timer fix (UUID without slot), tooltip fix for "only own debuffs" mode |
libdebuff.lua |
libs/ |
Immunity check, UnitDebuff() 8th return value caster, Lua 5.0 table limit workaround (11 tables to pfUI. namespace), Crash 132 fix, Player GUID caching |
unitframes.lua |
api/ |
Consistent DoNothing() pattern for lightweight cooldown frames |
nameplates.lua |
modules/ |
Consistent DoNothing() pattern, childs table reuse, indexed debuff timeout scan, quick exit optimization, Crash 132 fix |
nampower.lua |
modules/ |
Crash 132 fix |
superwow.lua |
modules/ |
Crash 132 fix |
actionbar.lua |
modules/ |
Crash 132 fix |
| File | Location | Changes |
|---|---|---|
libdebuff.lua |
libs/ |
Rogue PLAYER_COMBO_POINTS fix, always use GetDuration() for CP-abilities |
api.lua |
api/ |
Abbreviate() now supports 3 modes (off/2dec/1dec), 1dec always floors |
config.lua |
api/ |
Added castbardecimals option |
gui.lua |
modules/ |
Abbreviate Numbers dropdown, Castbar Timer Decimals dropdown |
nameplates.lua |
modules/ |
Smooth castbar (throttle fix), countdown timer, cache cleanup |
castbar.lua |
modules/ |
FormatCastbarTime() helper, respects castbardecimals config |
| File | Location | Changes |
|---|---|---|
superwow.lua |
modules/ |
Removed legacy pfDruidMana, added Target/ToT secondary mana bars, GetUnitField for all mana queries, respect Power Bar text settings |
nampower.lua |
modules/ |
Major cleanup: removed dead buff tracking, HoT detection, swing timer code |
| File | Location | Changes |
|---|---|---|
libdebuff.lua |
libs/ |
Memory leak fixes for lastCastRanks, lastFailedSpells |
unitframes.lua |
api/ |
In-place cache cleanup, CD frame scaling/positioning |
nameplates.lua |
modules/ |
Reusable debuffSeen table, Model+CooldownFrameTemplate |
cooldown.lua |
modules/ |
SetAlpha(1) for pfCooldownStyleAnimation == 1 |
config.lua |
api/ |
Added nameplates.debuffanim option |
gui.lua |
modules/ |
Added "Show Timer Animation" checkbox for nameplates |
REQUIRED:
- SuperWoW DLL
- Nampower DLL
Optional but Recommended:
- UnitXP_SP3 DLL (for accurate XP tracking)
- Install SuperWoW + Nampower
- Download pfUI Experiment build
- Extract to
Interface/AddOns/pfUI /reload- Check for errors in console
Type /run print(GetNampowerVersion()) - should show version number.
If nil, Nampower is not installed correctly!
- โ 40-man raids with 5+ druids (slot shifting stress test)
- โ Rapid target swapping with Ferocious Bite spam
โ ๏ธ Multi-caster tracking in AQ40/Naxx
- DEBUFF_ADDED race condition: Sometimes fires before AURA_CAST_ON_SELF processes
- Slot shifting bugs: Complex logic for removing/adding debuffs
- Combo point detection: Relies on PLAYER_COMBO_POINTS event timing
Added:
- โ
UnitDebuff() 8th return value:
caster("player"/"other"/nil) - โ Immunity check - no timer/icon shown if debuff wasn't actually applied
- โ Buff bar tooltip correctly identifies debuff slot in "only own debuffs" mode
- โ
/shifttestand/memcheckdebug commands for libdebuff troubleshooting
Fixed:
- ๐ง Player Buff Bar timer reset bug (UUID no longer includes slot for player buffs)
- ๐ง Lua 5.0 local variable limit (moved 11 tables to pfUI. namespace)
- ๐ง Crash 132 on logout (Credits: jrc13245) - affects libdebuff, nameplates, nampower, superwow, actionbar
- ๐ง Consistent DoNothing() pattern across all cooldown frame creation
Performance:
- โก
childstable reuse in nameplate scanner (avoids GC churn) - โก Indexed access instead of
pairs()for debuff timeout scanning - โก Quick exit if not in combat for threatcolor calculation
- โก Player GUID caching in libdebuff
Added:
- โ Castbar Timer Decimals setting (1 or 2 decimals)
- โ Abbreviate Numbers dropdown (Full / 2 Decimals / 1 Decimal)
- โ Nameplate castbar countdown (shows remaining time)
- โ Cache cleanup for hidden nameplates (prevents memory leaks)
Fixed:
- ๐ง Rogue combo point tracking (PLAYER_COMBO_POINTS was Druid-only)
- ๐ง Kidney Shot/Rupture duration (now always uses GetDuration() for CP-abilities)
- ๐ง Nameplate castbar stuttering (throttle only affects scanner, not updates)
Changed:
- ๐ง Abbreviate Numbers: 1 Decimal mode always rounds DOWN (4180 โ 4.1k)
- ๐ง Nameplate castbar: counts down instead of up
Added:
- โ Target Secondary Mana Bar (see Druid mana while in shapeshift form)
- โ Target-of-Target Secondary Mana Bar
- โ Secondary Mana Bars now respect Power Bar text settings
Changed:
- ๐ง Secondary Mana Bars now use
GetUnitField(guid, "power1")instead ofUnitMana() - ๐ง "Show Druid Mana Bar" setting now available for ALL classes (not just Druids)
Removed:
- โ Legacy
pfDruidManabar (replaced bypfPlayerSecondaryMana) - โ
UnitMana()extended return value fallback - โ Dead code in nampower.lua: buff tracking, HoT detection, swing timer
Added:
- โ Nameplate debuff timer animation support (pie/swipe effect)
- โ Target frame debuff animation improvements
- โ GUI option: Nameplates โ Show Timer Animation
Fixed:
- ๐ง Memory leak:
lastCastRanksnow cleaned up (>3s old entries) - ๐ง Memory leak:
lastFailedSpellsnow cleaned up (>2s old entries) - ๐ง Memory churn: Reusable
debuffSeentable in nameplates - ๐ง Memory churn: In-place cache cleanup in unitframes
- ๐ง cooldown.lua: Animation now visible when pfCooldownStyleAnimation == 1
Added:
- โ Event-driven debuff tracking (AURA_CAST, DEBUFF_ADDED, etc.)
- โ Combo point finisher support (Rip, Rupture, Kidney Shot)
- โ Carnage talent detection (Ferocious Bite refresh)
- โ Debuff overwrite pairs (Faerie Fire โ Faerie Fire Feral)
- โ Slot shifting algorithm (accurate icon placement)
- โ Multi-caster tracking (multiple Moonfires)
- โ Rank protection (Rank 1 can't overwrite Rank 10)
- โ Unique debuff system (Hunter's Mark, Scorpid Sting)
- โ Nampower GetUnitField() initial scan
- โ Combat indicator fix (works on player frame now)
Changed:
- ๐ง libdebuff.lua completely rewritten (464 โ 1594 lines)
- ๐ง UnitOwnDebuff() uses table lookup instead of tooltip scan
- โ
New Option: Enable Debuff Timers - Toggle for debuff timer display on nameplates
- Moved from hidden location (Appearance โ Cooldown โ "Display Debuff Durations") to Nameplates โ Debuffs
- All timer-related options are now grouped together for better discoverability
- โ
New Option: Show Timer Text - Toggle the countdown text (e.g., "12s") on debuff icons
- Previously always shown, now configurable
- โ Show Timer Animation - Existing pie-chart animation option, now properly grouped with other timer options
- โ
Live Config Updates - "Show Timer Animation" and "Show Timer Text" now update immediately
- Previously: Changes only applied after buffs/debuffs were refreshed
- Now: Toggling the option instantly shows/hides the animation and text on existing buffs/debuffs
- โ
Rogue & Druid Combo Point Tracking - Fixed duration calculation for combo point abilities
- Rupture, Kidney Shot, and Rip now correctly calculate duration based on combo points spent
- Added
PLAYER_COMBO_POINTSevent tracking for both Rogues AND Druids - Stores combo points before they're consumed, ensuring accurate duration calculation
- Fixes issue where abilities showed incorrect duration when combo points were already spent at cast time
- Fixed aggro indicator on "Player" frame not working properly.
- Fixed aggro and combat glow on player frames.
- Changed the Aggro indicator timer from 0.1 to 0.2 times per second (5 times per second is enough)
- Fixed the 40yard range check not working properly for Shamans and Druids in bear/cat form.
- Added 2 new buttons to the Nameplate menu: "Disable Hostile Nameplates in Friendly Zones" and "Disable Friendly Nameplates in Friendly Zones"
- changed version to 6.2.5 to push an update for everyone
- Feel free to check out https://github.com/me0wg4ming/pfUI/tree/enhanced_release - this is an experiment version with proper tracking for debuffs on current target (use on own risk)
- Fixed lag spikes in raids, raid frames should be now butter smooth and cause no lags
- Fixed a bug not updating hp/mana and buffs/debuffs properly.
- Removed a scan system that scanned always all 40 raid frames 10 times per second (worked out a better solution to track those)
- debuff tracking on enemys (for your own abilitys/spells) should be working properly too now
- โ
Resist/Miss/Dodge/Parry Detection - Spells that fail to land no longer create or update timers
- Detects: Miss, Resist, Dodge, Parry, Evade, Deflect, Reflect, Block, Absorb, Immune
- Timer is either blocked before creation or reverted if fail event arrives late
- โ
Public API:
libdebuff:DidSpellFail(spell)- Other modules can check if a spell recently failed- Returns true if spell failed within the last 1 second
- Used by turtle-wow.lua for refresh mechanics
- โ
Ferocious Bite Refresh Fix - Rip/Rake timers only refresh when Ferocious Bite actually hits
- Previously: Timer refreshed even on dodge/parry/miss
- Now: Uses
DidSpellFail()to verify hit before refreshing
- โ Conflagrate Refresh Fix - Immolate duration only reduced when Conflagrate actually hits
- โ Caster Inheritance - Refresh mechanics preserve existing caster info when not explicitly provided
- โ
Removed UNIT_CASTEVENT for DoT Timers - SuperWoW's instant event fires before resist/miss detection
- DoT timers now use standard hook-based fallback (compatible with resist detection)
- HoT timers (Rejuvenation, Renew, etc.) still use SuperWoW for instant detection (buffs can't be resisted)
- โ
Spell Rank Tracking - Tracks spell rank for all your DoTs/debuffs
- Uses
lastCastRankstable to preserve rank information across multiple event sources - Fixes race condition where SuperWoW UNIT_CASTEVENT fired before QueueFunction processed pending data
- Uses
- โ
Lower Rank Protection - Lower rank spells cannot overwrite higher rank timers
- Example: If Moonfire Rank 10 is active, casting Rank 5 will be blocked
- โ
Other Player Protection - Other players' casts cannot overwrite your debuff timers
- Your DoTs are tracked separately from other players' DoTs
- Multiple players can have their own Moonfire/Corruption on the same target
- โ
Shared Debuff Whitelist - Debuffs that are shared by all players update correctly:
- Warrior: Sunder Armor, Demoralizing Shout, Thunder Clap
- Rogue: Expose Armor
- Druid: Faerie Fire, Faerie Fire (Feral)
- Hunter: Hunter's Mark
- Warlock: Curse of Weakness/Recklessness/Elements/Shadow/Tongues/Exhaustion
- Priest: Shadow Weaving
- Mage: Winter's Chill
- Paladin: All Judgements
- โ Regrowth Duration Fix - Corrected duration from 21 to 20 seconds (matching actual Turtle WoW spell duration)
- โ
GetTime() Synchronization - All timing calls now use
pfUI.uf.now or GetTime()for consistent timing across all UI elements - โ
Instant-HoT Detection Fix - Fixed Rejuvenation/Renew not being detected when cast quickly after Regrowth
- Problem:
spell_queuewas overwritten before processing - Solution: Instant HoTs now processed immediately at cast hooks with
current_casttracking
- Problem:
- โ
SuperWoW UNIT_CASTEVENT Support - Precise Instant-HoT detection using UNIT_CASTEVENT
- Only fires on successful casts (not attempts), eliminating false triggers from GCD/range failures
- Graceful fallback to hook-based detection for players without SuperWoW
- โ
HealComm Compatibility - Full compatibility with standalone HealComm addon users
- 0.3s delay compensation for Regrowth messages
- Duplicate detection (0.5s window) prevents double timers
- โ PARTY Channel Support - HoT messages now sent to PARTY channel for 5-man dungeons
- โ
Target Castbar Zoom Fix - Fixed current target castbar not showing when zoom factor is enabled
- Multi-method target detection: alpha check,
istargetflag, andzoomedstate - Proper GUID lookup for target castbar info (was incorrectly using string "target")
- Multi-method target detection: alpha check,
- โ
Flicker/Vibration Fix - Eliminated nameplate flicker near zoom boundaries
- Alpha check changed from
== 1to>= 0.99(floating-point fix) - Zoom tolerance changed from
>= wto> w + 0.5(prevents oscillation)
- Alpha check changed from
- โ libdebuff Nil-Checks - Added safety checks to prevent errors when libdebuff data is unavailable
- โ
Error Handling - Added pcall wrapper for
GetSpellNameAndRankForIdto prevent error spam when spell ID not found
- โ Rip Duration (libdebuff.lua) - Now dynamically calculated based on combo points (10/12/14/16/18 seconds for 1-5 CP)
- โ Ferocious Bite Refresh (turtle-wow.lua) - Now refreshes both Rip AND Rake (previously only Rip), preserving existing duration
- โ Talent/Buff Energy Filter - Ignores energy gains from talents/buffs (e.g., Ancient Brutality and Tiger's Fury) to prevent tick timer reset from non-natural energy gains
- โ Chat Level Display Fix - Fixed targeting high-level players overwriting known level with -1. Now shows "??" for unknown levels instead of -1
- โ Nameplate Level Fix - Nameplates now use stored level from database after reload instead of showing "??"
- โ Nameplate Level Color - Level color now correctly uses difficulty color when loaded from database
- โ Chat Player Levels - Now disabled by default (was enabled)
- โ
40-Yard Range Check Fix - Fixed range check not working for raid/party frames due to throttle variable conflict (
this.tickvsthis.throttleTick) - โ Aggro Indicator Fix - Fixed aggro indicator not displaying properly on raid/party frames (same throttle issue)
- โ Aggro Detection Cache - Improved aggro cache to only cache positive results, allowing instant detection when aggro changes while maintaining performance
- โ Raid Frames with Group Display - Fixed HP/Mana not updating when "Use Raid Frames to display group members" was enabled without being in a raid
- โ
SuperWoW nil-check - Added nil-check for
SpellInfoin superwow.lua to prevent errors when SuperWoW is not installed - โ
Missing Event Registration - Added missing events for raid/party frames:
PARTY_MEMBER_ENABLE,PARTY_MEMBER_DISABLE,PLAYER_UPDATE_RESTING
- โ Share Button Warning - Shows message when Share module is disabled instead of doing nothing
- โ Hoverbind Button Warning - Shows message when Hoverbind module is disabled instead of doing nothing
- โ Central Raid/Party Event Handler - Replaced per-frame event registration with a centralized system using O(1) unitmap lookups instead of O(n) iteration. Reduces event processing from ~5,760 calls/sec to ~400 calls/sec in 40-man raids (97.5% improvement)
- โ Raid HP/Mana Update Fix - Fixed race condition where unitmap wasn't rebuilt after frame IDs were reassigned, causing HP/Mana bars to not update when players swap positions
- โ
OnUpdate Throttling - Added configurable throttles to reduce CPU usage:
- Nameplates: 0.1s throttle (target updates remain instant)
- Tooltip cursor following: 0.1s throttle
- Chat tab mouseover: 0.1s throttle
- Panel alignment: 0.2s throttle
- Autohide hover check: 0.05s throttle
- Libpredict cleanup: 0.1s throttle
- โ
Pushback Fix - Fixed spell pushback calculation: now correctly adds delay to
casttimeinstead ofstarttime, matching actual WoW behavior - โ Player GUID Caching - Caches player GUID on PLAYER_ENTERING_WORLD for efficient self-cast detection
- โ Hybrid Detection System - Uses libcast.db for player casts (handles SPELLCAST_DELAYED events) and SuperWoW's UNIT_CASTEVENT for NPC/other player casts
- โ 2-Decimal Precision - Castbar timer now displays with 2 decimal places (e.g., "1.45 / 2.50") for more precise timing
- โ Event-Based Detection - Replaced polling-based stealth detection with event-driven system using UNIT_CASTEVENT and PLAYER_AURAS_CHANGED
- โ Instant Cat Form Detection - Detects Cat Form via UNIT_CASTEVENT (spell ID 768) for immediate actionbar page switch
- โ Smart Buff Scanning - Only scans buffs when actually needed (entering Cat Form), eliminates 31-buff scan every frame
- โ Cached Variables - Caches stealth state to prevent redundant checks
- โ Friendly Player Classification - Fixed friendly players being classified as FRIENDLY_NPC, now correctly uses FRIENDLY_PLAYER for proper nameplate coloring and behavior
- โ Performance Throttle - 0.1s update throttle for non-target nameplates while keeping target nameplate updates instant
Modules by jrc13245
-
โ nampower.lua - Nampower DLL integration module:
- Spell Queue Indicator (shows queued spell icon near castbar)
- GCD Indicator
- Reactive Spell Indicator
- Enhanced buff tracking
- Requires Nampower DLL
-
โ unitxp.lua - UnitXP_SP3 DLL integration module:
- Line of Sight Indicator on target frame
- Behind Indicator on target frame
- OS Notifications for combat events
- Distance-based features
- Requires UnitXP_SP3 DLL
-
โ bgscore.lua - Battleground Score frame positioning:
- Movable BG score frame
- Position saving across sessions
- โ HasSuperWoW() - Detects SuperWoW DLL presence
- โ HasUnitXP() - Detects UnitXP_SP3 DLL presence
- โ HasNampower() - Detects Nampower DLL presence
- โ GetUnitDistance(unit1, unit2) - Returns distance using best available method (UnitXP or SuperWoW)
- โ UnitInLineOfSight(unit1, unit2) - Line of sight check via UnitXP
- โ UnitIsBehind(unit1, unit2) - Behind check via UnitXP
- โ /pfdll - Shows DLL status for SuperWoW, Nampower, and UnitXP with detailed diagnostics
- โ /pfbehind - Test command for Behind/LOS detection on current target
- โ TrackUnit API - Track group members on minimap (configurable)
- โ Raid Marker Targeting - Target units by raid marker ("mark1" to "mark8")
- โ GetUnitOwner - Get owner of pets/totems using "owner" suffix
- โ Enhanced SpellInfo - Wrapper returning structured spell data
- โ Clickthrough API - Toggle clicking through corpses
- โ Autoloot API - Control autoloot setting
- โ GetPlayerBuffSpellId - Get spell ID from buff index
- โ LogToCombatLog - Add custom entries to combat log
- โ SetLocalRaidTarget - Set raid markers only visible to self
- โ GetItemCharges - Get item charges (SuperWoW returns as negative)
- โ GetUnitWeaponEnchants - Get weapon enchant info on any unit
- โ Player Level Display - Shows player level next to names in chat (color-coded by difficulty)
- โ Tab Mouseover Throttle - 0.1s throttle for chat tab hover effects
All new features are configurable via /pfui:
Unit Frames โ SuperWoW Settings:
- Track Group on Minimap
Unit Frames โ Nampower Settings:
- Show Spell Queue Indicator
- Spell Queue Icon Size
- Show Reactive Spell Indicator
- Reactive Indicator Size
- Enhanced Buff Tracking
Unit Frames โ UnitXP Settings:
- Show Line of Sight Indicator
- Show Behind Indicator
- Enable OS Notifications
Chat โ Text:
- Enable Player Levels
- โ superwow_active Variable - Fixed inconsistent SuperWoW detection across modules (nameplates, castbar, librange, unitframes)
- โ Unitmap Race Condition - Fixed HP/Mana not updating when raid members swap positions
- โ Friendly Nameplate Color - Fixed friendly players using NPC color instead of player color
Turtle WoW includes TBC spells in the Vanilla client. This version includes all TBC buff indicators:
- โ Commanding Shout indicator
- โ Misdirection indicator
- โ Earth Shield indicator
- โ Prayer of Mending indicator
Version: 6.2.0
Release Date: January 10, 2026
Compatibility: Turtle WoW 1.18.0
Optional DLLs: SuperWoW, Nampower, UnitXP_SP3 (enhanced features when available)
- Download Latest Version
- Unpack the Zip file
- Rename the folder "pfUI-master" to "pfUI"
- Copy "pfUI" into Wow-Directory\Interface\AddOns
- Restart Wow
pfUI 6.0.0 includes optional integrations with client-side DLLs for enhanced functionality. These DLLs are fully supported on Turtle WoW:
Repository: https://github.com/balakethelock/SuperWoW
Provides:
- Enhanced castbar detection via UNIT_CASTEVENT
- UnitPosition for distance calculations
- SetMouseoverUnit for improved targeting
- SpellInfo for spell data queries
Repository: https://gitea.com/avitasia/nampower
Provides:
- Spell queue indicator
- GCD indicator
- Reactive spell detection
- Enhanced cast information
Repository: https://codeberg.org/konaka/UnitXP_SP3
Provides:
- Line of Sight detection
- Behind detection
- Accurate distance calculations
- OS notifications
Use /pfdll in-game to check which DLLs are detected.
/pfui Open the configuration GUI
/pfdll Show DLL detection status (SuperWoW, Nampower, UnitXP)
/pfbehind Test Behind/LOS detection on current target
/clickthrough Toggle clickthrough mode (or /ct)
/share Open the configuration import/export dialog
/gm Open the ticket Dialog
/rl Reload the whole UI
/farm Toggles the Farm-Mode
/pfcast Same as /cast but for mouseover units
/focus Creates a Focus-Frame for the current target
/castfocus Same as /cast but for focus frame
/clearfocus Clears the Focus-Frame
/swapfocus Toggle Focus and Target-Frame
/pftest Toggle pfUI Unitframe Test Mode
/abp Addon Button Panel
pfUI supports and contains language specific code for the following gameclients.
- English (enUS)
- Korean (koKR)
- French (frFR)
- German (deDE)
- Chinese (zhCN)
- Spanish (esES)
- Russian (ruRU)
- pfQuest A simple database and quest helper
- WIM (continued) Give whispers an instant messenger feel
- pfUI-eliteoverlay Add elite dragons to unitframes
- pfUI-fonts Additional fonts for pfUI
- pfUI-CustomMedia Additional textures for pfUI
- pfUI-Gryphons Add back the gryphons to your actionbars
What does "pfUI" stand for?
The term "pfui!" is german and simply stands for "pooh!", because I'm not a
big fan of creating configuration UI's, especially not via the Wow-API
(you might have noticed that in ShaguUI).
How can I donate?
You can donate via GitHub or Ko-fi
How do I report a Bug?
Please provide as much information as possible in the Bugtracker.
If there is an error message, provide the full content of it. Just telling that "there is an error" won't help any of us.
Please consider adding additional information such as: since when did you got the error,
does it still happen using a clean configuration, what other addons are loaded and which version you're running.
When playing with a non-english client, the language might be relevant too. If possible, explain how people can reproduce the issue.
How can I contribute? Report errors and issues in the Bugtracker. Please make sure to have the latest version installed and check for conflicting addons beforehand.
I have bad performance, what can I do?
Version 6.0.0 includes significant performance optimizations. If you still experience issues:
- Disable "Frame Shadows" in Settings โ Appearance โ Enable Frame Shadows
- Check
/pfdllto see which DLLs are active (some features require DLLs) - Disable all AddOns but pfUI and enable one-by-one to identify conflicts
- Report issues via the Bugtracker
Where is the happiness indicator for pets?
The pet happiness is shown as the color of your pet's frame. Depending on your skin, this can either be the text or the background color of your pet's healthbar:
- Green = Happy
- Yellow = Content
- Red = Unhappy
Since version 4.0.7 there is also an additional icon that can be enabled from the pet unit frame options.
Can I use Clique with pfUI?
This addon already includes support for clickcasting. If you still want to make use of clique, all pfUI's unitframes are already compatible to Clique-TBC. For Vanilla, a pfUI compatible version can be found Here. If you want to keep your current version of Clique, you'll have to apply this Patch.
Where is the Experience Bar?
The experience bar shows up on mouseover and whenever you gain experience, next to left chatframe by default. There's also an option to make it stay visible all the time.
How do I show the Damage- and Threatmeter Dock?
If you enabled the "dock"-feature for your external (third-party) meters such as DPSMate or KTM, then you'll be able to toggle between them and the Right Chat by clicking on the ">" symbol on the bottom-right panel.
Why is my chat always resetting to only 3 lines of text?
This happens if "Simple Chat" is enabled in blizzards interface settings (Advanced Options).
Paste the following command into your chat to disable that option: /run SIMPLE_CHAT="0"; pfUI.chat.SetupPositions(); ReloadUI()
How can I enable mouseover cast?
On Vanilla, create a macro with "/pfcast SPELLNAME". If you also want to see the cooldown, You might want to add "/run if nil then CastSpellByName("SPELLNAME") end" on top of the macro.
Everything from scratch?! Are you insane?
Most probably, yes.
- Shagu - Original pfUI creator (https://github.com/shagu/pfUI)
- me0wg4ming - pfUI fork maintainer and Turtle WoW enhancements
- jrc13245 - Nampower, UnitXP, and BGScore module integration (https://github.com/jrc13245/)
- SuperWoW Team - SuperWoW framework development
- avitasia - Nampower DLL development
- konaka - UnitXP_SP3 DLL development
- Turtle WoW Team - For the amazing Vanilla+ experience
- Community - Bug reports, feature suggestions, and testing
Same as original pfUI - free to use and modify.
Version: 7.6.2
Release Date: February 6, 2026
Compatibility: Turtle WoW 1.18.0
Status: Stable
