Files
BlizzNameplatesPlus/modules/visualguard.lua
T
2026-09-27 19:05:08 +02:00

208 lines
7.0 KiB
Lua

BNP = BNP or {}
-- Safe one-shot native visual repair ---------------------------------------
-- UI texture patches can replace the files behind Blizzard's native
-- Nameplate-Border/Nameplate-Glow paths without changing the texture paths
-- returned by the client. Keep private copies of the original Vanilla assets
-- inside BNP so those patches cannot silently reskin or blank the plates.
--
-- Apply them only when a plate is initialized/shown. There is intentionally NO
-- heartbeat and no layout/parent/anchor enforcement here, so BNP never fights
-- WorldFrame movement while the player/camera is moving.
local BORDER_TEXTURE = "Interface\\AddOns\\BlizzNameplatesPlus\\media\\classic_nameplate_border.tga"
local GLOW_TEXTURE = "Interface\\AddOns\\BlizzNameplatesPlus\\media\\classic_nameplate_glow.tga"
local DARK_BORDER_R, DARK_BORDER_G, DARK_BORDER_B, DARK_BORDER_A = 0.3, 0.3, 0.3, 0.9
local function IsTotemIconOnly(plate)
return plate and plate.BNPTotemLastKey and
BNP.AreTotemIndicatorsEnabled and BNP:AreTotemIndicatorsEnabled()
end
local function RestoreBorder(plate)
local border = plate and plate.border
if not border then return end
if border.GetTexture and border.SetTexture and border:GetTexture() ~= BORDER_TEXTURE then
border:SetTexture(BORDER_TEXTURE)
end
local hidden = BNP.IsNameplateBorderHidden and BNP:IsNameplateBorderHidden()
if hidden then
if border.IsShown and border.Hide and border:IsShown() then border:Hide() end
plate.BNPBorderHidden = true
return
end
-- Restore only the visibility state BNP owns. The historical visual guard
-- also repairs borders hidden by skin patches when the hide option is off.
if border.IsShown and border.Show and not border:IsShown() then
border:Show()
end
plate.BNPBorderHidden = nil
end
local function RestoreGlow(plate)
local glow = plate and plate.glow
if not glow then return end
-- Do not show the region here. Blizzard/BNP still controls its visibility
-- through the normal mouseover path; only its source art is protected.
if glow.GetTexture and glow.SetTexture and glow:GetTexture() ~= GLOW_TEXTURE then
glow:SetTexture(GLOW_TEXTURE)
end
end
local function SetBorderVertexColor(border, r, g, b, a)
if not border or not border.SetVertexColor then return end
if border.GetVertexColor then
local oldR, oldG, oldB, oldA = border:GetVertexColor()
if math.abs((oldR or 1) - r) < 0.001
and math.abs((oldG or 1) - g) < 0.001
and math.abs((oldB or 1) - b) < 0.001
and math.abs((oldA or 1) - a) < 0.001 then
return
end
end
border:SetVertexColor(r, g, b, a)
end
local function ApplyBorderStyle(plate)
local border = plate and plate.border
if not border then return end
if BNP.IsNameplateBorderHidden and BNP:IsNameplateBorderHidden() then return end
if BNP.IsDarkNameplateBorderEnabled and BNP:IsDarkNameplateBorderEnabled() then
-- Match ShaguTweaks' default Darkened UI color, but touch only the native
-- nameplate border. Healthbars, glows, castbars and icons stay unchanged.
SetBorderVertexColor(border, DARK_BORDER_R, DARK_BORDER_G, DARK_BORDER_B, DARK_BORDER_A)
else
-- This option is authoritative for the nameplate border. In particular,
-- switching it off must restore the original gold even when ShaguTweaks'
-- global Darkened UI mode previously tinted this texture.
SetBorderVertexColor(border, 1, 1, 1, 1)
end
end
local function ApplyLevelVisibility(plate)
local level = plate and plate.level
if not level then return end
local hidden = BNP.IsNameplateLevelHidden and BNP:IsNameplateLevelHidden()
if hidden then
if level.IsShown and level.Hide and level:IsShown() then level:Hide() end
plate.BNPLevelHidden = true
return
end
if plate.BNPLevelHidden then
if level.Show then level:Show() end
plate.BNPLevelHidden = nil
end
end
local function ApplyOptionalNativeVisibility(plate)
if not plate or IsTotemIconOnly(plate) then return end
RestoreBorder(plate)
ApplyLevelVisibility(plate)
end
local function ApplyHealthbarBackground(plate)
local healthbar = plate and plate.healthbar
if not healthbar then return end
local enabled = BNP.IsBlackHealthbarBackgroundEnabled and
BNP:IsBlackHealthbarBackgroundEnabled()
local background = plate.BNPHealthbarBackground
-- Keep the default path allocation-free. The extra texture is created only
-- after the user enables the option, then reused whenever this plate is
-- recycled for another unit.
if not enabled then
if background and background.IsShown and background:IsShown() then
background:Hide()
end
return
end
if not background then
-- BORDER sits above BNP's target glow (BACKGROUND) but below the StatusBar
-- fill, so the unfilled portion stays truly black even on the target.
background = healthbar:CreateTexture(nil, "BORDER")
background:SetTexture(0, 0, 0, 1)
background:SetAllPoints(healthbar)
plate.BNPHealthbarBackground = background
end
if background.GetParent and background:GetParent() ~= healthbar then
background:SetParent(healthbar)
background:ClearAllPoints()
background:SetAllPoints(healthbar)
end
if background.IsShown and not background:IsShown() then background:Show() end
end
function BNP:RepairNativeNameplateVisuals(plate)
if not plate then return end
if IsTotemIconOnly(plate) then return end
RestoreBorder(plate)
RestoreGlow(plate)
ApplyBorderStyle(plate)
ApplyLevelVisibility(plate)
ApplyHealthbarBackground(plate)
end
function BNP:RefreshNameplateBorderStyle()
local plate
for plate in pairs(BNP.plates or {}) do
self:RepairNativeNameplateVisuals(plate)
end
end
function BNP:RefreshNameplateLevelVisibility()
local plate
for plate in pairs(BNP.plates or {}) do
if plate then
ApplyLevelVisibility(plate)
if BNP.RefreshAuraLayoutForPlate then BNP:RefreshAuraLayoutForPlate(plate) end
if BNP.RefreshImmunityLayoutForPlate then BNP:RefreshImmunityLayoutForPlate(plate) end
end
end
end
function BNP:RefreshHealthbarBackground()
local plate
for plate in pairs(BNP.plates or {}) do
ApplyHealthbarBackground(plate)
end
end
if BNP.libnameplate then
table.insert(BNP.libnameplate.OnInit, function(plate)
BNP:RepairNativeNameplateVisuals(plate or this)
end)
table.insert(BNP.libnameplate.OnShow, function(plate)
BNP:RepairNativeNameplateVisuals(plate or this)
end)
-- libnameplate already runs this list at 10 Hz. The default path returns
-- immediately; only enabled hide options need to enforce native visibility
-- against Blizzard recycling/show calls.
table.insert(BNP.libnameplate.OnUpdate, function(plate)
local current = plate or this
if not current or not current.IsShown or not current:IsShown() then return end
local hideBorder = BNP_DB and BNP_DB.hideNameplateBorder
local hideLevel = BNP_DB and BNP_DB.hideNameplateLevel
if not hideBorder and not hideLevel and not current.BNPBorderHidden and not current.BNPLevelHidden then
return
end
ApplyOptionalNativeVisibility(current)
end)
end