v8.4.0 — themes grid + Carbon, DLL capability tooling, cleanup - #1
v8.4.0 — themes grid + Carbon, DLL capability tooling, cleanup#1ShikawaLePaladin wants to merge 24 commits into
Conversation
… fix dead links Themes: - Rework the firstrun "choose profile" step into a data-driven button grid. It now surfaces all built-in profiles instead of a hardcoded 4. Adding a new theme is one list entry + one profile table; the grid auto-sizes the window. - Expose the previously-hidden Adapta and Light profiles in the wizard. - Add a new dark high-contrast "Carbon" theme (derived from Slim's layout), registered in both the initial assignment and the VARIABLES_LOADED loader (required, since pfUI_profiles is a SavedVariable) with new_module_positions. Cleanup / fixes: - README: correct the Requirements section — Nampower is the only hard dependency; SuperWoW and UnitXP_SP3 are optional/feature-detected. Add an OctoWoW note and mention /pfdll. - Repoint in-game clickable URLs (config website buttons, libdebuff nampower install links) from the deleted me0wg4ming repo to ShikawaLePaladin/pfUI. - Fix firstrun profile hint to the real menu path (Settings > General > Profile). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d control - /pfdll now probes and reports the specific API surfaces each DLL exposes (SuperWoW 2.x: UnitNameplate/CursorPosition/GetSpeed/CanLootUnit/..., Nampower: GetSpellRec/GetUnitField/GetSpellIdCooldown/GetSpellModifiers/..., plus UnitXP_SP3 presence). This turns "is SuperWoW/UnitXP allowed on this server?" into a one command in-game answer - useful on private servers like OctoWoW. - Add /pfnpspread (alias /pfnameplatespread) to cycle SuperWoW 2.0's NameplateMotion CVar (overlap / default / smart / compact spread). Gated behind UnitNameplate as a SuperWoW-2.0 proxy; SetCVar persists across sessions. Fully absent otherwise. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Bump pfUI.toc / pfUI-tbc.toc to 8.4.0 and version badge to the fork. - Add 8.4.0 changelog entry (themes grid + Carbon, /pfdll probing, /pfnpspread, requirements/link fixes) in the existing README style. - Update Author line to credit the ShikawaLePaladin continuation while keeping Shagu (original) and me0wg4ming (fork) attribution. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: decd07718c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| SLASH_PFNAMEPLATESPREAD1 = "/pfnpspread" | ||
| SLASH_PFNAMEPLATESPREAD2 = "/pfnameplatespread" |
There was a problem hiding this comment.
Register the nameplate spread slash aliases globally
When SuperWoW 2.0 is present, this module body runs under pfUI:GetEnvironment() via pfUI:LoadModule, so bare SLASH_* assignments are stored on the pfUI environment table rather than _G. WoW's slash command discovery reads the global SLASH_PFNAMEPLATESPREAD* names, so /pfnpspread and /pfnameplatespread will not be recognized even though SlashCmdList gets a handler; assign these through _G or use the existing RegisterSlashCommand helper.
Useful? React with 👍 / 👎.
Adds a self-contained Trinket Bar module showing the two equipped trinkets with a live cooldown swipe, click-to-use, and hover tooltip. Off by default; toggled via Unit Frames > General > Trinket Bar Settings. Movable through the standard pfUI unlock system. Follows the totems.lua conventions (COOLDOWN_FRAME_TYPE + CooldownFrame_SetTimer, so pfUI's cooldown text/styling applies automatically; PLAYER_LOGOUT shutdown to avoid crash 132). Uses only stock 1.12 inventory API, so it works with or without DLLs; cooldown stays ms-accurate through Nampower when present. - new module: modules/trinketbar.lua (+ init/modules.xml include) - config defaults: trinketbar="0", trinketbar_size="32" (api/config.lua) - GUI options under the DLL/Nampower settings block (modules/gui.lua) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a small coin icon on the nameplate of lootable corpses. Off by default, toggled under Nameplates. The check runs in the existing central OnUpdate but is throttled to ~0.4s per plate (loot state only changes on death) and wrapped in pcall so an unexpected CanLootUnit signature can never break the shared nameplate loop. cfg.lootable is force-disabled when CanLootUnit is absent, so this is fully inert without SuperWoW 2.0. Investigation note: the planned "refactor nameplate discovery to UnitNameplate()" was dropped as unnecessary — plate->unit association already uses SuperWoW's frame:GetName(1) throughout, so a risky rewrite of the WorldFrame scan would add risk for no real gain. Added a genuinely-new feature instead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause: the registered events (UNIT_INVENTORY_CHANGED, BAG_UPDATE_COOLDOWN, ACTIONBAR_UPDATE_COOLDOWN) don't fire when a trinket's on-use cooldown starts from being clicked directly on this custom bar - none of them cover "equipped item used outside a bag/action button". Confirmed in-game: cooldown swipe never appeared after using a trinket. Fix: poll GetInventoryItemCooldown on a throttled (0.2s) OnUpdate, same approach the default Blizzard character pane trinket slots use. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…not a GUID
Confirmed in-game: CanLootUnit(rawGuid) silently returned false, while
CanLootUnit("target") returned 1 (truthy) on an actually-lootable corpse.
CanLootUnit(), called with no argument, errors ("Usage: CanlootUnit(\"unit\")"),
confirming it strictly requires a bound unit token.
Fix: track mouseoverGuid alongside the existing targetGuid in frameState, and
only query CanLootUnit with "target"/"mouseover" when the plate's cached GUID
matches one of those - never with the raw GUID. This limits the indicator to
plates that are currently targeted or moused-over (SuperWoW 2.0 doesn't seem to
expose a way to query loot state for arbitrary units), but it now actually works
instead of being silently dead code.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Compared against every other module that creates a Cooldown frame (bags.lua, totems.lua, actionbar.lua) - all of them set pfCooldownType and pfCooldownStyleAnimation. Without those, pfUI's central cooldown.lua hook treats the frame as "foreign" and (by default settings) does nothing to it, so neither the forced swipe nor pfUI's styled countdown text ever apply - matches the user's report of no visible timer on the icon (only the plain tooltip cooldown text). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t it) Confirmed in-game: even limited to the targeted/moused-over plate (the only case the fixed unit-token version could support), the indicator still never showed. SuperWoW 2.0's CanLootUnit doesn't provide what this feature needs reliably on this client. Rather than ship a checkbox that silently does nothing, pulling it entirely - clean removal, no dead config/GUI/texture left behind. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds manual /roll-based SR/MS/OS/Transmog loot distribution as used by guilds running loot council instead of Blizzard's native Need/Greed/Pass. This is a distinct system from the native group-loot popup already handled above in this file - not a duplicate, just grouped in the same module. Ported into pfUI conventions rather than copied as-is: CreateBackdrop/SkinButton styling instead of raw backdrop code, UpdateMovable instead of a hand-rolled drag script, config-driven duration/autoclose (C.loot.council.*) instead of hardcoded values, and PLAYER_LOGOUT event cleanup to avoid crash 132. Fixed a real bug from the original addon while porting: it used its own English-only class-name-keyed color table (broke on non-English clients since GetRaidRosterInfo's class name is localized). Now uses the real fileName-keyed RAID_CLASS_COLORS via GetRaidRosterInfo's 6th return value. Off by default - opt in under Loot > Loot Council Settings. New /pflootcouncil slash command toggles the window. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes "attempt to call method 'GetHeight' (a nil value)" at addonbuttons.lua:149. The scanner only checked that _G[button_name] was non-nil, not that it was still a valid frame object - a global can exist under that name without exposing frame methods (e.g. another addon reused the name, or the owning addon's frame got torn down/replaced). Pre-existing bug, unrelated to this session's other changes; surfaced by the user's specific addon mix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Investigated docking it like DPSMate (pfUI.thirdparty.meters system) but OctoMeter has a fundamentally different architecture: multiple simultaneous windows with magnet-snapping and its own flat-texture theme system, vs DPSMate's single fixed-name scroll list. Reparenting/SetAllPoints into pfUI.chat.right would fight OctoMeter's own window management. Instead: push pfUI's current border/background colors into OctoMeter's own Database settings (borderColor/bgColor) and call Window:ApplyThemeToAll(), so it visually blends with the active pfUI theme while staying fully independent (movable, resizable, multi-window, snapping all still OctoMeter's own). OctoMeter already ships its own minimap button, picked up automatically by pfUI's existing addon-button organizer, so no extra toggle button was added. On by default (matches other skin-only thirdparty integrations), toggle under Thirdparty > Integrations > "OctoMeter (Skin)". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…p nil-guard addonbuttons.lua: the existing GetHeight guard (previous commit) only covered one call site. Same class of bug hit two more in the wild (confirmed via user's in-game errors): ProcessButtons' IsVisible() call and RestoreButton's SetParent call on a stale top-frame name. Added a shared IsValidGlobalFrame() helper (checks GetObjectType, not just non-nil) and applied it at every _G[button_name] site, including UpdatePanel's cleanup pass so stale entries get pruned instead of silently re-erroring every update. roll.lua (loot council): - Fixed "attempt to concatenate a nil value" on the SR/MS/OS/TM button tooltip by nil-guarding both operands. - Restored the item-icon retry logic dropped during the LootBlare port: a freshly-seen item isn't always cached client-side yet, so GetItemInfo can return nil name/icon on the first call. Now retries every ~0.5s (up to ~10s) until it resolves, same reason the original addon had its own CheckItem polling loop that I'd simplified away. Not pushed - holding per instruction until told to push.
…lookup Root cause of "attempt to index field '?'" on click: the button OnClick/OnEnter closures captured the loop variable `cap` directly instead of storing it on the button frame - this codebase's own established pattern (see totems.lua's this.id) avoids exactly that, for good reason: it broke in practice here, confirmed by the user's repeated in-game errors. Fixed by storing b.cap and reading this.cap inside the handlers instead of the captured loop variable. Also simplified the item-icon lookup: use ExtractItemLink's already-clean "item:id:..." string directly instead of re-extracting a fixed number of ':'-separated fields (fragile on item links with a different field count - enchants/gems/unique IDs/extra server fields). Removed the arbitrary 20-retry give-up cap on the icon-resolution poll; it's already naturally bounded by council.isRolling (the roll duration timer). Not pushed - holding per instruction.
…ItemInfo In-game evidence: GameTooltip:SetHyperlink() rendered the full item tooltip (stats, quality, etc.) proving the item was already client-cached, yet GetItemInfo() on the exact same link string kept returning nil across many retries. GetHyperlink/SetHyperlink is far more tolerant of link format than GetItemInfo - if this server's item links carry extra fields beyond stock vanilla's, GetItemInfo may choke on them. Now extracts just the bare numeric item ID via "item:(%d+)" and passes that number to GetItemInfo instead of the full link string - the simplest form it accepts, nothing extra left to trip over. council.itemLink (the full link, used for the icon's tooltip/dressup/chat-insert) is untouched. Not pushed - holding per instruction.
Two attempted fixes (full link, then bare item ID) haven't resolved the icon issue, and I can't reproduce this OctoWoW-specific behavior locally. Rather than guess a third time, print exactly what GetItemInfo receives and returns so the next test gives real data. To remove once understood. Not pushed - holding per instruction.
… position In-game debug data confirmed the real bug: GetItemInfo's name (1st return) resolves correctly, but the icon consistently came back nil at the position stock vanilla's documented signature would put it (9th/10th) - even though the item was fully client-cached (its tooltip rendered completely via SetHyperlink). This server's GetItemInfo return layout doesn't match what I assumed, and the original LootBlare addon I ported from had the exact same fixed-position assumption (also likely wrong/untested for icons). New ResolveItemIcon(itemId) helper: try the dedicated GetItemIcon() API first (feature-detected), then fall back to scanning ALL of GetItemInfo's return values for whatever actually looks like a texture path (a string starting with "Interface\") instead of trusting one fixed index. Works regardless of which position this server's GetItemInfo puts the icon at. Removed the temporary debug prints now that the root cause is understood. Not pushed - holding per instruction.
Previous fix (GetItemIcon + string-path scan) still didn't resolve the icon. Rather than guess a 4th time, dump every return value with its type/index - possible the icon comes back as a numeric fileID rather than a string path, which the current scan would silently skip. Not pushed - holding per instruction.
Confirmed via debug: this server's GetItemInfo only returns 3 values (name, link, quality) - no icon at all, unlike stock vanilla's 11. Nampower exposes richer item data via GetItemStats(id, true) (already used elsewhere in this file for itemLevel) - dump its full field set to check for an icon-shaped key before giving up on a GetItemInfo-based approach entirely. Not pushed - holding per instruction.
…otBlare step)
Root cause finally identified: on this server, GetItemInfo() only returns full
item data (icon included) once the client has already fully resolved that item
via a tooltip query - called cold, it returns just a lightweight 3-field result
(name/link/quality), which is exactly what debug logging showed every time.
The original LootBlare addon (which the user confirmed works correctly for
icons) primes this: it calls SetHyperlink() on a hidden tooltip and polls until
the tooltip text resolves, before ever calling GetItemInfo. I'd dropped that
step while porting - my code called GetItemInfo directly on a cold item.
Restored via pfUI's own libtipscan scanner (SetHyperlink on
libtipscan:GetScanner("lootcouncil")) right when a roll starts, before the
first GetItemInfo attempt. Cleaned up the now-answered GetItemStats field-dump
debug spam; left one compact confirmation print for this next test.
Not pushed - holding per instruction.
…setup Side-by-side in-game test was conclusive: the original LootBlare addon resolved the icon correctly on the exact same item, at the exact same moment, while my libtipscan-based priming still failed. The one concrete difference: LootBlare's discover tooltip uses SetOwner(UIParent, "ANCHOR_PRESERVE"), while libtipscan's shared scanner uses SetOwner(WorldFrame, "ANCHOR_NONE"). Replaced the libtipscan-based priming with a dedicated hidden GameTooltip (pfLootCouncilItemProbe) using the exact same owner/anchor LootBlare uses. Also re-prime on every retry tick (not just once at roll start), matching LootBlare's ShowFrame loop which re-touches the tooltip continuously rather than a single one-shot call. Not pushed - holding per instruction.
…bare ID Investigated AtlasLoot per suggestion: it doesn't dynamically resolve icons at all (own bundled static database of classic loot icons, not usable here), and it only hooks the real GameTooltip/ItemRefTooltip/TmogTooltip - not any custom-created tooltip, so it isn't quietly assisting either LootBlare's or this addon's own probe tooltip. Not the explanation, but re-reading LootBlare's code against my own more carefully surfaced a real untested gap: LootBlare's SetItemInfo calls GetItemInfo(itemLinkArg) with the FULL link string, while my code had switched to a bare numeric ID early on (before the priming fix existed) and never tried full-link + priming together. ResolveItemIcon now takes itemLinkOrId generically (GetItemIcon/GetItemInfo get whatever was passed; GetItemStats specifically extracts a numeric ID from it, since Nampower's API wants a plain ID there). Not pushed - holding per instruction.
unitframes.lua already reads and acts on C.unitframes[unit].selfdebuff at
several points (lines ~207, 2182, 2236, 2256, 2495) - filtering the debuff
icons shown on a unit frame down to only the player's own casts (exactly what
a Warlock wants for tracking their own DoTs on target without noise from other
casters). The logic was fully working but had no GUI checkbox - only the
separate buffbar.tdebuff module's own copy of this feature was exposed
(Unit Frames > General > "Show Only Own Debuffs").
Added the checkbox to the per-unit Debuffs section (inside the
unitframeSettings loop), so it now applies to target/focus/party/raid/etc.
Config default ("0") was already set for every relevant unit via the existing
ufs loop in api/config.lua - no default changes needed.
Not pushed - holding per instruction.
First release of the ShikawaLePaladin continuation of the fork. Four workstreams,
each committed separately.
🎨 Themes
surfaces every built-in profile and auto-sizes the window. Adding a theme = 1 list
entry + 1 profile table.
VARIABLES_LOADEDloader (required —pfUI_profilesis a SavedVariable) with its ownnew_module_positions.🔌 DLL capability tooling
/pfdllnow probes and reports the individual API surfaces each mod exposes(SuperWoW 2.x / Nampower / UnitXP_SP3). Quick way to see what a private server permits.
/pfnpspreadcycles SuperWoW 2.0'sNameplateMotionCVar (overlap / default /smart / compact). Gated behind
UnitNameplate; inert on older/absent SuperWoW.🧹 Fixes
me0wg4mingrepo to this fork.No Lua runtime available offline — changes were structurally validated (bracket balance,
Lua 5.0 idioms, closure-in-loop) but the Carbon look and the 7-button wizard grid
layout should be eyeballed in-game. Run
/pfdllto confirm which DLLs OctoWoW allows.🤖 Generated with Claude Code