Skip to content

Update for WoW 12.0.0 (Midnight) Compatibility#461

Open
Amadeus- wants to merge 58 commits intoLuxocracy:masterfrom
Amadeus-:midnight
Open

Update for WoW 12.0.0 (Midnight) Compatibility#461
Amadeus- wants to merge 58 commits intoLuxocracy:masterfrom
Amadeus-:midnight

Conversation

@Amadeus-
Copy link
Copy Markdown

@Amadeus- Amadeus- commented Jan 24, 2026

Please note that I have not tested this version on the classic servers. I tested it as much as I could on retail against normal mobs in the open world, but not bosses or special encounters.

Summary

This update brings full compatibility with World of Warcraft 12.0.0 (Midnight), addressing the major API changes introduced in the Midnight expansion's secret value system and combat log restrictions.

Key changes:

  • Implemented secret value handling for health, power, and aura data that are now protected during combat
  • Migrated health bars to use native StatusBar widgets that accept secret values at the C++ level
  • Disabled COMBAT_LOG_EVENT_UNFILTERED processing (no longer available to addons in 12.0.0+)
  • Updated all TOC files to Interface 120000 with multi-version support
  • Removed legacy version-specific TOC files (Classic, BCC, WOTLKC, Cata, Mists, Mainline suffixes)
  • Added API compatibility wrappers for deprecated functions

Technical Details: Secret Value Handling

In WoW 12.0.0+, certain unit information (health, power, aura details) returns "secret values" during combat. These values cannot be:

  • Used in arithmetic operations (e.g., health / healthmax will error)
  • Compared with numbers (e.g., health < healthmax will error)
  • Used as table keys

Solution Approach

  1. Native StatusBar for Health/Power Bars: The core solution uses WoW's native StatusBar widget, which has SecretArguments = "AllowedWhenTainted" at the C++ level. This allows SetValue() and SetMinMaxValues() to accept secret values directly without Lua ever needing to read them back.

  2. Safe Value Caching: The unit table now includes "safe" versions of health/power values:

    • unit.healthSafe / unit.healthmaxSafe
    • unit.powerSafe / unit.powermaxSafe

    These are populated with the numeric value when available, or a fallback when the value is secret.

  3. Helper Functions: New helper functions in NeatPlatesHubHelpers:

    • SafeNumber(value, fallback) - Returns numeric value or fallback if secret
    • SafeHealthPercent(unit) - Safe health percentage calculation
    • SafeIsDamaged(unit) - Safe "health < healthmax" comparison
    • SafeHasHealth(unit) - Safe "health > 0" check
  4. Aura Data Handling: Direct field access from C_UnitAuras.GetAuraDataByIndex() instead of AuraUtil.UnpackAuraData() which fails on secret values. All aura field usages now check issecretvalue() before comparisons or table key operations.

Combat Log Restriction

COMBAT_LOG_EVENT_UNFILTERED is no longer available to addons only in 12.0.0+. This addon now:

  • Skips registration of this event on Midnight clients
  • Interrupt tracking still works via per-unit UNIT_SPELLCAST_INTERRUPTED events

API Migrations

  • C_SpellBook.IsSpellKnown replaces deprecated IsSpellKnown
  • C_NamePlate.SetNamePlateSize replaces separate friendly/enemy size functions
  • SetGradient with ColorMixin replaces deprecated SetGradientAlpha
  • C_CombatLog.GetCurrentEventInfo replaces CombatLogGetCurrentEventInfo

Testing Notes

  1. Health Bar Display: Verify health bars update correctly during combat when values become secret
  2. Aura Widget: Check that buffs/debuffs display correctly; some aura filtering may be less precise with secret spellIds
  3. Power Bar: Confirm power bars show/hide correctly and update during combat
  4. Interrupt Display: Verify spell interrupts still show on nameplates (uses UNIT_SPELLCAST_INTERRUPTED)
  5. Threat Coloring: Test threat-based coloring which relies on health comparisons
  6. Custom Text: Verify health percentage and health value text displays work

Breaking Changes

  • Combat log parsing disabled: Any functionality that relied on parsing COMBAT_LOG_EVENT_UNFILTERED (beyond interrupt detection) will not work in 12.0.0+

Files Modified

Core Files (Secret Value Handling)

  • NeatPlates/NeatPlatesCore.lua - Version detection, safe value helpers, secret-aware unit updates
  • NeatPlates/NeatPlatesStatusbar.lua - Complete rewrite with native StatusBar for 12.0.0+
  • NeatPlates/NeatPlatesUtility.lua - Minor updates
  • NeatPlatesHub/Helpers.lua - New SafeNumber, SafeHealthPercent, SafeIsDamaged, SafeHasHealth helpers

Hub Functions (Safe Comparisons)

  • NeatPlatesHub/functions/Alpha.lua - Use safe helpers for health-based alpha
  • NeatPlatesHub/functions/Color.lua - Use safe helpers for health-based coloring
  • NeatPlatesHub/functions/Core.lua - Safe value compatibility
  • NeatPlatesHub/functions/Filter.lua - Safe value compatibility
  • NeatPlatesHub/functions/Scale.lua - Use safe helpers for health-based scaling
  • NeatPlatesHub/functions/Style.lua - Safe value compatibility
  • NeatPlatesHub/functions/Text.lua - Use safe helpers for health text display
  • NeatPlatesHub/functions/Widgets.lua - Safe value compatibility

Widgets (Aura Secret Handling)

  • NeatPlatesWidgets/AuraWidget.lua - Direct aura field access, issecretvalue checks
  • NeatPlatesWidgets/ComboPointWidget.lua - API compatibility
  • NeatPlatesWidgets/HealerTrack.lua - API compatibility
  • NeatPlatesWidgets/ResourceWidget.lua - API compatibility
  • NeatPlatesWidgets/TankTrack.lua - API compatibility

TOC Files Updated (Interface 120000)

  • NeatPlates/NeatPlates.toc
  • NeatPlatesHub/NeatPlatesHub.toc
  • NeatPlatesWidgets/NeatPlatesWidgets.toc
  • NeatPlates_Alvara/NeatPlates_Alvara.toc
  • NeatPlates_BlizzardPlates/NeatPlates_BlizzardPlates.toc
  • NeatPlates_ClassicPlates/NeatPlates_ClassicPlates.toc
  • NeatPlates_Graphite/NeatPlates_Graphite.toc
  • NeatPlates_Grey/NeatPlates_Grey.toc
  • NeatPlates_Neon/NeatPlates_Neon.toc
  • NeatPlates_Quatre/NeatPlates_Quatre.toc
  • NeatPlates_Renaitre/NeatPlates_Renaitre.toc
  • NeatPlates_Roth/NeatPlates_Roth.toc
  • NeatPlates_Simple/NeatPlates_Simple.toc
  • NeatPlates_Slim_Horizontal/NeatPlates_Slim_Horizontal.toc
  • NeatPlates_Slim_Vertical/NeatPlates_Slim_Vertical.toc

Deleted Files (Legacy TOC files)

  • 67 version-specific TOC files removed (-Classic, -BCC, -WOTLKC, -Cata, -Mists, -Mainline, -TBC suffixes)
  • NeatPlates_Renaitre/Fonts/._RobotoCondensed-Bold.ttf (macOS metadata file)

- Implement native StatusBar for health/power bars to handle secret values
- Add SafeNumber, SafeHealthPercent, SafeIsDamaged helpers for safe comparisons
- Store safe cached values (healthSafe, powermaxSafe, etc.) in unit table
- Handle secret values in aura data (issecretvalue checks before table keys)
- Disable COMBAT_LOG_EVENT_UNFILTERED (restricted to damage meters in 12.0.0)
- Update all TOC files to Interface 120000 with multi-version support
- Remove 67 legacy version-specific TOC files (Classic, BCC, Cata, etc.)
- Add SetGradient compatibility wrapper (replaces deprecated SetGradientAlpha)
- Add C_SpellBook.IsSpellKnown and C_NamePlate.SetNamePlateSize wrappers
@Amadeus-
Copy link
Copy Markdown
Author

Amadeus- commented Jan 26, 2026

Follow-up: Additional WoW 12.0 Secret Value Fixes

Tested on retail 12.0 against normal mobs in the open world. Not tested on classic servers or boss encounters.


Summary

This follow-up commit addresses additional Secret Value issues discovered during live testing that weren't covered in the initial PR:

  1. Raid Target Icons - Now display correctly during combat
  2. Aura/Debuff Icons - Now display on nameplates during combat
  3. Aura Duration Timers - Now show countdown numbers on aura icons
  4. Aura Ownership Filtering - Version-aware handling for "Show Mine" filter

Fix 1: Raid Target Icons (Skull, X, Moon, etc.)

Problem:

NeatPlates/NeatPlatesCore.lua:1220: table index is secret

GetRaidTargetIndex() returns a secret value during combat. The code was using it as a table key: RaidIconList[raidIconIndex]

Solution:

  • Changed from SetTexCoord() with coordinate table lookup to SetSpriteSheetCell()
  • SetSpriteSheetCell() has SecretArguments = "AllowedWhenTainted" and accepts secret values directly
  • Store the raw (potentially secret) index and pass it directly to the display API

Files Changed:

  • NeatPlates/NeatPlatesCore.lua - UpdateIndicator_RaidIcon() function

Fix 2: Aura/Debuff Display

Problem:
Aura icons were not appearing on nameplates during combat. All aura data fields (name, spellId, icon, duration, expirationTime, isFromPlayerOrPlayerPet) are secret values in 12.0.

Solution:
Multiple changes to handle secret aura data:

  1. Validity Check: Changed from checking aura.texture (secret) to aura.auraInstanceID (always readable)

  2. Icon Display: Pass secret icon value directly to SetTexture() which accepts secrets

  3. Caster Check: Use isFromPlayerOrPlayerPet field with issecretvalue() guard instead of UnitIsUnit("player", caster)

Files Changed:

  • NeatPlatesWidgets/AuraWidget.lua - UpdateIconGrid() and related functions

Fix 3: Aura Duration Timers

Problem:
Duration countdown numbers were not appearing on aura icons because duration and expirationTime are secret values.

Solution:
Use WoW 12.0's new duration object APIs:

local durationObject = C_UnitAuras.GetAuraDuration(unitToken, auraInstanceID)
cooldown:SetCooldownFromDurationObject(durationObject)
cooldown:SetHideCountdownNumbers(false)  -- Enable built-in countdown
  • SetCooldownFromDurationObject() has SecretArguments = "AllowedWhenTainted"
  • Uses the Cooldown frame's built-in countdown display instead of custom text
  • Added SetCountdownFont("GameFontHighlightSmallOutline") for appropriately sized numbers on small aura icons

Behavior:

WoW Version Duration Display Method
Pre-12.0 Custom TimeLeft FontString (original)
12.0+ Built-in Cooldown countdown numbers

Files Changed:

  • NeatPlatesWidgets/AuraWidget.lua - UpdateIcon() and CreateAuraIcon() functions

Bonus: Debug System

Added a debug window system for future troubleshooting (disabled by default):

Commands:

  • /npdebug auras - Toggle aura debug output
  • /npdebug raidicon - Toggle raid icon debug output
  • /npdebug show - Open scrollable debug window
  • /npdebug clear - Clear debug log

Files Changed:

  • NeatPlates/NeatPlatesUtility.lua - Debug window UI
  • NeatPlates/NeatPlatesPanel.lua - Slash commands

Secret Value API Reference

APIs that ACCEPT secret values (SecretArguments = "AllowedWhenTainted"):

  • texture:SetTexture(secretFileID)
  • texture:SetSpriteSheetCell(secretIndex, rows, cols)
  • cooldown:SetCooldownFromDurationObject(durationObject)
  • statusbar:SetValue(secretValue)
  • statusbar:SetMinMaxValues(secretMin, secretMax)

APIs that DO NOT accept secret values:

  • table[secretIndex] - Cannot use as table key
  • secretValue > 0 - Cannot compare
  • UnitIsUnit("player", secretUnit) - Cannot compare units
  • if secretValue then - Cannot use in boolean context

Detection:

if issecretvalue(value) then
    -- Value is secret, cannot use in comparisons
end

- Guard all UnitIsUnit/UnitName/UnitClass calls against secret values
  in NeatPlatesCore.lua, NeatPlatesUtility.lua, and Text.lua
- Remove old PolledHideIn-based TimeLeft timer from aura icons
- Standardize on Blizzard's built-in CooldownFrame countdown numbers
- Pass raw GetAuraApplicationDisplayCount value directly to SetText
  instead of SafeValue stripping secret values during combat
- Remove SetUseAuraDisplayTime from durationObject path to prevent
  conflict with SetCooldownFromDurationObject's internal aura timing
- Fix legacy fallback: enable SetUseAuraDisplayTime and remove +0.25 hack
- Use native SetTimerDuration API for C++-level smooth bar animation
  instead of Lua OnUpdate with raw epoch-millisecond timestamps
- Normalize min/max to (0, durationSeconds) for pre-12.0 fallback
- Root cause: float precision loss with 13-digit ms timestamps in
  StatusBar's internal fill fraction computation
- Show standard Blizzard spell tooltip on aura icon mouseover
- Use SetUnitAuraByAuraInstanceID with SetSpellByID fallback
- Enable mouse hover but pass clicks through to nameplate
- Dismiss tooltip when aura expires mid-hover
- Add toggle setting in aura options (enabled by default)
- Display interrupter name inline as "Interrupted (NAME)" with class color on the cast bar.
- Uses dedicated interrupterName FontString with SetFormattedText and C_ClassColor.GetClassColor to handle secret values at the C++ level.
- Left-aligned when name is known, centered when showing only "Interrupted".
- Please note that, as of WoW 12.0.0, only the names of those in your group or raid will appear as an "interruptor".  If someone outside the group or raid does the interruption, their name will not appear.  It will just say "Interrupted".
- Filters nameplate auras to only those Blizzard flags as important (via INCLUDE_NAME_PLATE_ONLY), matching Platynator's behavior. Enabled by default. Located under "Buffs and Debuffs" in settings.
Blizzard's 12.0 Secret Values system makes all aura data (name, spellId, icon, etc.) unreadable during combat, breaking custom aura list matching (Exclude, Mine Only, All). Only auraInstanceID remains non-secret but is per-instance, not per-spell.

- Hide Additional Auras UI on 12.0+ with explanatory notice
- Short-circuit GetPrefixPriority() on 12.0+ clients
- Preserve saved aura list data for pre-12.0 client compatibility
- Add /npdebug secrettest diagnostic command
- Add missing GameTooltip:Show() call to OnEnter scripts in NeatPlatesCheckButtonTemplate, NeatPlatesColorButtonTemplate, and NeatPlatesPanelTipTemplate in NeatPlates.xml.
- Extend tooltip hover area to include labels for all widget types (checkboxes, sliders, dropdowns, color pickers) in NeatPlatesUtility.lua. Clicking checkbox labels now also toggles the checkbox.
- Blizzard added ADVENTURER and TRAVELER tokens to RAID_CLASS_COLORS in 11.2.x. NeatPlates copies all keys from that table but lacked locale entries for these new tokens, causing 25+ AceLocale warnings on load.
- Add nil checks for activetheme.SetSubText, activetheme.SetScale, activetheme.SetUnitName, and NeatPlatesHubFunctions.SetStyleNamed calls in NeatPlatesCore.lua. These Hub delegate functions may not be present in the activetheme table during initialization or when NeatPlatesHub hasn't fully loaded. Also guard activetheme.Default.hitbox access in UpdateNameplateSize timer callback.
- Guard all uses of unit.guid as table keys in RangeWidget.lua with issecretvalue() checks to comply with WoW 12.0.0 secret values API. Falls back safely when guids are secret during combat.
- Move ShowImportantAurasOnly declaration before function definition to fix Lua upvalue capture (variable was always nil)
- Remove duplicate declaration so SetAuraOptions updates correct variable
- Re-register UNIT_AURA on Blizzard UnitFrame after UnregisterAllEvents so Blizzard's AurasFrame continues processing auras internally
- Add GetBlizzardImportantAuras() to read Blizzard's filtered aura whitelist and filter NeatPlates auras against it
- Guard color.r/g/b comparisons with issecretvalue() check to handle WoW 12.0.0+ secret values during combat. Skips quest objective detection when colors are protected instead of erroring.
- Guard all table lookups using UnitName() results with issecretvalue() checks in HealerTrack, Color, and RangeWidget to prevent crashes when unit names are restricted during combat.
* Enforce minimum hitbox width based on active theme's visual elements so Blizzard's HitTestFrame fully covers the NeatPlates healthbar/castbar/borders. Uses Blizzard's own anchor math: effective click width = SetNamePlateSize(W) - 4.
* Disable mouse on NeatPlates StatusBar frames (EnableMouse(false)) so clicks pass through to Blizzard's HitTestFrame for proper unit targeting.
* Add /npdebug hitbox command with color-coded visual overlays, mouse-focus tracker, and detailed frame size reporting for diagnosing click issues.
- Guard against WoW 12.0.0 secret table values in NeatPlatesUtility.lua by checking issecretvalue(color) before indexing color.r/g/b fields. Add issecretvalue guard for unit.name comparison in Color.lua.
…alth-based coloring is impossible with secret values in 12.0.0+. The plain "Percent Health" option remains and works correctly
…oW 12.0.0)

- Add issecretvalue() guards to prevent errors from secret number/table values returned by WoW APIs during combat:
- NeatPlatesUtility.lua: Guard tempThreat and playerThreat comparisons in GetGroupThreatLeader() and GetRelativeThreat() (threat functions)
- NeatPlatesUtility.lua: Guard secret tooltip line data (leftColor, leftText, lineType) in quest objective parsing to prevent indexing secret tables
- Add nil-safety for lastQuestTitle when earlier lines are skipped```
…tibility

- Hub Core.lua/Alpha.lua: Guard bare issecretvalue() calls with existence check to prevent crashes on pre-12.0 clients
- NeatPlatesPanel.lua: Add C_SpecializationInfo.GetSpecialization wrapper for 12.0.0+ where the global was removed, fixing profile switching
…bat safety

- Hub Color.lua: Fix unguarded UnitIsUnit() calls in threat color and warning border functions (reuse existing guarded var, restructure elseif)
- Hub Core.lua: Guard UnitIsUnit() in ThreatExceptions fixate detection
- ComboPointWidget: Guard UnitGUID table keys and UnitPower/UnitPowerMax comparisons to prevent combat errors
- ResourceWidget: Guard UnitPower/UnitPowerMax in all class GetPower functions (Druid, Rogue, Paladin, Default)
- TankTrack: Guard 3 UnitIsUnit boolean tests and 7 UnitGUID table key usages across Classic and Retail code paths
- HealerTrack: Guard unit.guid before WidgetList table operations
- NeatPlatesCore: Guard UnitThreatSituation before ThreatReference table key lookup, UnitIsFriend/UnitIsEnemy before boolean tests in target toggle, UnitSelectionColor before arithmetic with cached reaction fallback
- NeatPlatesUtility: Guard valueToString against secret value arithmetic
- ArenaWidget: Guard unit.rawName before GetArenaIndex in PvP combat
…ellInfo

- NeatPlatesCore.lua: Pass 'spellidentifier' (the function parameter) to C_Spell.GetSpellInfo instead of 'spellname' (undefined, always nil)
- Replace GUID-based target detection with UnitIsUnit() in ResourceWidget to handle WoW 12.0.0+ secret values returned by UnitGUID() during combat.
- Add threat percentage widget debug instrumentation with [Threat] and [ThreatInit] output categories, toggled via /npdebug threat. Add pause/resume toggle button to the debug output window for easier copy-paste of debug logs.
- Hide "Show Tug-o-Threat Indicator" and "Show Threat Percentage" settings on 12.0.0+ since UnitDetailedThreatSituation no longer returns usable data from addon code. - Add combat detection fallback for remaining threat features when UnitThreatSituation returns nil, using target-chain heuristics
…n type green.

(The original file is left remaining for those who might prefer it.)
…onal Resource Display

- Add "Show Power Bar" checkbox that displays a thin light cyan StatusBar showing the player's power (mana/energy/rage) on the target's nameplate, below the class resource icons
- Power bar uses pcall-wrapped UnitPower/UnitPowerMax with native StatusBar secret value handling for 12.0.0+ compatibility
- Add "Refill Brightness (%)" slider (0-100%, default 80%) to control the brightness of cooldown swipe texture during resource refilling
- Remove " Profile" suffix from profile names in settings panel
- Remove "(BETA)" label from Personal Resource Display heading
- Remove erroneous SetFont(1, .8, 0) call in dropdown highlight code
- Add missing ItemTooltip:Hide() after SetOwner in settings tooltips
- Remove unnecessary global names from nameplate carrier frames
- Add "Refill Brightness (%)" slider (0-100%, default 80%) to control cooldown swipe brightness during resource refilling
- Fix power bar vertical position (was too far below resource icons)
- Fix "Show Power Bar" checkbox left-alignment with "Show On:"
- Push cast bar and all casting elements down 10px on target nameplate when power bar is visible to prevent overlap
- Fix cast bar offset scoping across do blocks (forward declaration)
- Fix non-target plates retaining target's cast bar offset
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant