From aea1f734caddef00e866643a341138398577f412 Mon Sep 17 00:00:00 2001 From: Bluewhale1337 <295648290+Bluewhale1337@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:55:30 +0200 Subject: [PATCH] fix: resolve raid class coloring, identity cache, and player range detection issues --- HealBot.lua | 63 +++++++++++++++++++++++++++-------- HealBot_Controller_Events.lua | 16 ++++++++- HealBot_Controller_Range.lua | 2 +- HealBot_Model.lua | 35 ++++++++++++++++++- HealBot_View_Layout.lua | 21 +++++++++--- README.md | 2 ++ 6 files changed, 118 insertions(+), 21 deletions(-) diff --git a/HealBot.lua b/HealBot.lua index 93e6548..86524a1 100644 --- a/HealBot.lua +++ b/HealBot.lua @@ -203,22 +203,59 @@ end -- Spell parsing and casting functions moved to HealBot_Controller_Spells.lua +HealBot_ClassMap = nil + +function HealBot_InitClassMap() + HealBot_ClassMap = { + ["DRUID"] = "DRUID", ["Druid"] = "DRUID", + ["HUNTER"] = "HUNTER", ["Hunter"] = "HUNTER", + ["MAGE"] = "MAGE", ["Mage"] = "MAGE", + ["PALADIN"] = "PALADIN", ["Paladin"] = "PALADIN", + ["PRIEST"] = "PRIEST", ["Priest"] = "PRIEST", + ["ROGUE"] = "ROGUE", ["Rogue"] = "ROGUE", + ["SHAMAN"] = "SHAMAN", ["Shaman"] = "SHAMAN", + ["WARLOCK"] = "WARLOCK", ["Warlock"] = "WARLOCK", + ["WARRIOR"] = "WARRIOR", ["Warrior"] = "WARRIOR", + } + if HEALBOT_DRUID then HealBot_ClassMap[HEALBOT_DRUID] = "DRUID" end + if HEALBOT_HUNTER then HealBot_ClassMap[HEALBOT_HUNTER] = "HUNTER" end + if HEALBOT_MAGE then HealBot_ClassMap[HEALBOT_MAGE] = "MAGE" end + if HEALBOT_PALADIN then HealBot_ClassMap[HEALBOT_PALADIN] = "PALADIN" end + if HEALBOT_PRIEST then HealBot_ClassMap[HEALBOT_PRIEST] = "PRIEST" end + if HEALBOT_ROGUE then HealBot_ClassMap[HEALBOT_ROGUE] = "ROGUE" end + if HEALBOT_SHAMAN then HealBot_ClassMap[HEALBOT_SHAMAN] = "SHAMAN" end + if HEALBOT_WARLOCK then HealBot_ClassMap[HEALBOT_WARLOCK] = "WARLOCK" end + if HEALBOT_WARRIOR then HealBot_ClassMap[HEALBOT_WARRIOR] = "WARRIOR" end +end + -- HealBot_UnitClass: Returns English class string for a unit. function HealBot_UnitClass(unit) - local locClass, enClass = UnitClass(unit) - if enClass then return string.upper(enClass) end - - -- Fallback for Vanilla 1.12 where enClass is nil - if locClass == HEALBOT_DRUID then return "DRUID" - elseif locClass == HEALBOT_HUNTER then return "HUNTER" - elseif locClass == HEALBOT_MAGE then return "MAGE" - elseif locClass == HEALBOT_PALADIN then return "PALADIN" - elseif locClass == HEALBOT_PRIEST then return "PRIEST" - elseif locClass == HEALBOT_ROGUE then return "ROGUE" - elseif locClass == HEALBOT_SHAMAN then return "SHAMAN" - elseif locClass == HEALBOT_WARLOCK then return "WARLOCK" - elseif locClass == HEALBOT_WARRIOR then return "WARRIOR" + if not unit then return nil end + if not HealBot_ClassMap then HealBot_InitClassMap() end + + -- 1. If player self, query "player" directly + if unit == "player" or UnitIsUnit(unit, "player") then + local locClass, enClass = UnitClass("player") + if enClass and enClass ~= "" then return string.upper(enClass) end + if locClass and HealBot_ClassMap[locClass] then return HealBot_ClassMap[locClass] end + if locClass then return string.upper(locClass) end end + + -- 2. If raid member, query GetRaidRosterInfo (server authoritative English class token) + local _, _, raidIdx = string.find(unit, "^raid(%d+)$") + if raidIdx and GetNumRaidMembers() > 0 then + local _, _, _, _, class, fileName = GetRaidRosterInfo(tonumber(raidIdx)) + if fileName and fileName ~= "" then + return string.upper(fileName) + elseif class and HealBot_ClassMap[class] then + return HealBot_ClassMap[class] + end + end + + -- 3. General fallback via UnitClass API + local locClass, enClass = UnitClass(unit) + if enClass and enClass ~= "" then return string.upper(enClass) end + if locClass and HealBot_ClassMap[locClass] then return HealBot_ClassMap[locClass] end return locClass end diff --git a/HealBot_Controller_Events.lua b/HealBot_Controller_Events.lua index 5682a44..bad14f4 100644 --- a/HealBot_Controller_Events.lua +++ b/HealBot_Controller_Events.lua @@ -172,7 +172,19 @@ function HealBot_OnUpdate(this, arg1) for unitID in pairs(powerToRefresh) do HealBot_Action_RefreshPower(unitID) end - + -- Periodic resolution of units with missing class identity + if HealBot_Model and HealBot_Model.unresolvedUnits and next(HealBot_Model.unresolvedUnits) then + HealBot_UnresolvedTimer = (HealBot_UnresolvedTimer or 0) + arg1 + if HealBot_UnresolvedTimer >= 0.5 then + HealBot_UnresolvedTimer = 0 + for u in pairs(HealBot_Model.unresolvedUnits) do + if HealBot_Model:UpdateUnitIdentity(u) then + HealBot_View_DirtyUnits[u] = true + end + end + end + end + if HealBot_EquipChangeTimer > 0 then HealBot_EquipChangeTimer = HealBot_EquipChangeTimer - arg1 if HealBot_EquipChangeTimer <= 0 then @@ -274,6 +286,7 @@ local HealBot_EventHandlers = { HealBot_OnEvent_PlayerTargetChanged(this) end, ["PARTY_MEMBERS_CHANGED"] = function(this) + HealBot_Model:RefreshUnit("player") for _, unit in ipairs(HealBot_Model.partyMembers) do HealBot_Model:RefreshUnit(unit) end @@ -284,6 +297,7 @@ local HealBot_EventHandlers = { HealBot_OnEvent_PartyMembersChanged(this) end, ["RAID_ROSTER_UPDATE"] = function(this) + HealBot_Model:RefreshUnit("player") for _, unit in ipairs(HealBot_Model.partyMembers) do HealBot_Model:RefreshUnit(unit) end diff --git a/HealBot_Controller_Range.lua b/HealBot_Controller_Range.lua index 86c12af..ae03b1a 100644 --- a/HealBot_Controller_Range.lua +++ b/HealBot_Controller_Range.lua @@ -33,7 +33,7 @@ function HealBot_Range_Check(unit, range) return _rangeCache[range][unit] end - if ( unit == "player" or string.find(unit, "^Test") ) then + if ( unit and (unit == "player" or UnitIsUnit(unit, "player") or string.find(unit, "^Test")) ) then return_val = 1; elseif HealBot_Integrations_ClassicAPI_Active and UnitDistanceSquared and UnitInLineOfSight then local inSight = UnitInLineOfSight("player", unit) diff --git a/HealBot_Model.lua b/HealBot_Model.lua index 7ebfc74..8b66dad 100644 --- a/HealBot_Model.lua +++ b/HealBot_Model.lua @@ -47,7 +47,10 @@ HealBot_Model = { -- Integration maps unitGUIDs = {}, -- unit -> GUID - guidUnits = {} -- GUID -> unit + guidUnits = {}, -- GUID -> unit + + -- Delayed resolution queue + unresolvedUnits = {} } -------------------------------------------------------------------------------- @@ -87,6 +90,7 @@ end -- HealBot_Model:Initialize: Pre-allocates the unit state dictionary. function HealBot_Model:Initialize() + for k in pairs(self.unresolvedUnits) do self.unresolvedUnits[k] = nil end self:InitUnitState("player") self:InitUnitState("target") self:InitUnitState("pet") @@ -149,7 +153,36 @@ function HealBot_Model:UpdateUnitIdentity(unit) local oldName = self.units[unit].name local oldEnglishClass = self.units[unit].englishClass local name = UnitName(unit) + + -- If UnitName is not ready, attempt raid roster fallback for raid units + if not name or name == "Unknown" then + local _, _, raidIdx = string.find(unit, "^raid(%d+)$") + if raidIdx and GetNumRaidMembers() > 0 then + local rName = GetRaidRosterInfo(tonumber(raidIdx)) + if rName and rName ~= "" and rName ~= "Unknown" then + name = rName + end + end + end + + -- If name is still nil, retain oldName if unit exists + if not name and oldName and UnitExists(unit) then + name = oldName + end + local englishClass = HealBot_UnitClass(unit) + + -- If name is identical, do NOT overwrite an existing valid englishClass with nil + if oldName and name == oldName and not englishClass and oldEnglishClass then + englishClass = oldEnglishClass + end + + -- Track unresolved units (unit exists with a name, but missing englishClass) + if name and not englishClass then + self.unresolvedUnits[unit] = true + else + self.unresolvedUnits[unit] = nil + end if oldName ~= name or oldEnglishClass ~= englishClass then self.units[unit].name = name diff --git a/HealBot_View_Layout.lua b/HealBot_View_Layout.lua index d6785c0..cd1e040 100644 --- a/HealBot_View_Layout.lua +++ b/HealBot_View_Layout.lua @@ -69,10 +69,20 @@ function HealBot_HealthColor(unit, hlth, maxhlth) end local colorMode = HealBot_Config.bcolormode[HealBot_Config.Current_Skin] or 1 + local engClass = nil + if colorMode == 2 and not string.find(unit, "pet") then + engClass = HealBot_Model and HealBot_Model.units[unit] and HealBot_Model.units[unit].englishClass + if not engClass then + engClass = HealBot_UnitClass(unit) + if engClass and HealBot_Model and HealBot_Model.units[unit] then + HealBot_Model.units[unit].englishClass = engClass + end + end + end + if colorMode == 2 and string.find(unit, "pet") then r, g, b = 0.4, 0.9, 0.6 -- Mint color - elseif colorMode == 2 and HealBot_Model and HealBot_Model.units[unit] and HealBot_Model.units[unit].englishClass and RAID_CLASS_COLORS and RAID_CLASS_COLORS[HealBot_Model.units[unit].englishClass] then - local engClass = HealBot_Model.units[unit].englishClass + elseif colorMode == 2 and engClass and RAID_CLASS_COLORS and RAID_CLASS_COLORS[engClass] then r = RAID_CLASS_COLORS[engClass].r g = RAID_CLASS_COLORS[engClass].g b = RAID_CLASS_COLORS[engClass].b @@ -845,14 +855,15 @@ function HealBot_Action_PartyChanged() if GetNumRaidMembers() > 0 then for j = 1, 40 do local unit = "raid" .. j; - local Class = UnitClass(unit); - local ProcessUnit = 0; - local PossibleEmerg = 1; local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(j); if not name then name = "not known" end if not class then class = "not known" end if not subgroup then subgroup = "not known" end + local Class = UnitClass(unit) or class; + local ProcessUnit = 0; + local PossibleEmerg = 1; + if HealBot_EmergInc[Class] == 1 then ProcessUnit = 1; end diff --git a/README.md b/README.md index 148453d..bafac05 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,8 @@ Default installation path: `C:\Program Files\World of Warcraft\Interface\AddOns\ * **Feature - Shapeshift Spell Queue** - Built a native spell queue system for Druid auto-unshifting. Bypasses the "Cannot cast while shapeshifted" error and server lag when AutoUnshift is enabled, firing the heal seamlessly the exact millisecond the form is dropped. Now completely unified to use the standard casting API for maximum reliability across all client setups. * **Bug Fix - CDC Config List** - Fixed an uninitialized dropdown list array that prevented the CDC class monitor configuration from saving correctly. * **Bug Fix - Color Picker Accuracy** - Removed an undocumented multiplier hack on default textures that was artificially brightening debuff bar colors and overriding the user's selected colors from the color picker. +* **Bug Fix - Raid Self-Range & Transparency** - Fixed player health bar appearing transparent in raid instances by checking `UnitIsUnit(unit, "player")` in range detection, preventing false out-of-range failures when player is represented by a `raidX` token. +* **Bug Fix - Raid Class Coloring & Identity Cache** - Fixed missing and delayed raid class colors by querying authoritative server data (`GetRaidRosterInfo`) for raid members, preventing model identity cache wipes, adding a throttled resolution retry in `OnUpdate`, and providing on-demand class color fallbacks in `HealBot_HealthColor`. **v1.6.5** * **Performance Update - Mana Tracking** - Added a fast-path redraw pipeline for unit power changes. This optimization prevents full frame redraws when players naturally regenerate or consume mana, resolving severe FPS drops in 40-man raids while tracking mana.