BNP = BNP or {} local fallbackColors = { WARRIOR = { 0.78, 0.61, 0.43 }, MAGE = { 0.41, 0.80, 0.94 }, ROGUE = { 1.00, 0.96, 0.41 }, DRUID = { 1.00, 0.49, 0.04 }, HUNTER = { 0.67, 0.83, 0.45 }, SHAMAN = { 0.00, 0.44, 0.87 }, PRIEST = { 1.00, 1.00, 1.00 }, WARLOCK = { 0.58, 0.51, 0.79 }, PALADIN = { 0.96, 0.55, 0.73 }, } local function GetColor(class) if RAID_CLASS_COLORS and RAID_CLASS_COLORS[class] then local c = RAID_CLASS_COLORS[class] return c.r, c.g, c.b end local c = fallbackColors[class] if c then return c[1], c[2], c[3] end end local function Enabled() if BNP.AreClassColorsEnabled then return BNP:AreClassColorsEnabled() end return not BNP_DB or BNP_DB.classColors ~= false end local function ClearClassCache(plate) if not plate then return end plate.BNPClassColorApplied = nil plate.BNPClassColorToken = nil plate.BNPClassGUID = nil plate.BNPClassR = nil plate.BNPClassG = nil plate.BNPClassB = nil end local function ResolvePlateUnit(plate) if not plate or not plate.GetName then return nil, nil end local token = plate:GetName(1) if not token or not UnitExists(token) then return token, nil end local exists, guid = UnitExists(token) if exists then return token, guid end return token, nil end local function ApplyClassColor(plate) if not Enabled() then ClearClassCache(plate) return false end if not plate or not plate.healthbar then return false end local token, guid = ResolvePlateUnit(plate) -- BNP only owns PLAYER class colors. -- NPC/neutral/friendly-NPC colors stay completely under Blizzard control. if not token or not guid or not UnitIsPlayer(token) then ClearClassCache(plate) return false end local _, class = UnitClass(token) local r, g, b = GetColor(class) if not r then ClearClassCache(plate) return false end plate.BNPClassColorApplied = true plate.BNPClassColorToken = token plate.BNPClassGUID = guid plate.BNPClassR = r plate.BNPClassG = g plate.BNPClassB = b plate.healthbar:SetStatusBarColor(r, g, b) return true end BNP.ApplyClassColor = ApplyClassColor local function EnforceClassColor(plate) if not Enabled() then return end if not plate or not plate.healthbar or not plate.BNPClassGUID then return end local token, guid = ResolvePlateUnit(plate) -- Never enforce a cached color after Blizzard recycled the frame. if not token or not guid or guid ~= plate.BNPClassGUID or not UnitIsPlayer(token) then ClearClassCache(plate) return end local r, g, b = plate.healthbar:GetStatusBarColor() if math.abs(r - plate.BNPClassR) > 0.01 or math.abs(g - plate.BNPClassG) > 0.01 or math.abs(b - plate.BNPClassB) > 0.01 then plate.healthbar:SetStatusBarColor( plate.BNPClassR, plate.BNPClassG, plate.BNPClassB ) end end if BNP.libnameplate then table.insert(BNP.libnameplate.OnInit, function(plate) local current = plate or this if not current then return end ClearClassCache(current) ApplyClassColor(current) local bar = current.healthbar if bar and not current.BNPClassColorHooked then local oldValueChanged = bar:GetScript("OnValueChanged") bar:SetScript("OnValueChanged", function() if oldValueChanged then oldValueChanged() end EnforceClassColor(current) end) current.BNPClassColorHooked = true end end) table.insert(BNP.libnameplate.OnShow, function(plate) local current = plate or this if not current then return end ClearClassCache(current) ApplyClassColor(current) end) end -- Blizzard may rewrite player colors during combat/threat updates. -- Re-apply only while the plate still resolves to the SAME player GUID. -- If a recycled frame now represents an NPC/neutral unit, drop the cache -- immediately and never touch its Blizzard color. local elapsed = 0 local updater = CreateFrame("Frame") updater:SetScript("OnUpdate", function() elapsed = elapsed + arg1 if elapsed < 0.10 then return end elapsed = 0 if not Enabled() then return end local plate for plate in pairs(BNP.plates) do if plate:IsShown() and plate.healthbar then local token, guid = ResolvePlateUnit(plate) if plate.BNPClassGUID then EnforceClassColor(plate) elseif token and guid and UnitIsPlayer(token) then ApplyClassColor(plate) end end end end)