Implemented modular external addon integration system for UnitXP, Nampower, and SuperWoW support.

This commit is contained in:
Bluewhale1337
2026-08-17 23:33:20 +02:00
parent 58f593947e
commit dc2f0ca089
8 changed files with 208 additions and 9 deletions
+5
View File
@@ -388,6 +388,11 @@ function HealBot_OnEvent_PlayerTargetChanged(this)
end
function HealBot_OnEvent_PartyMembersChanged(this)
HealBot_Model:PreserveStateByGUID()
HealBot_Integrations_PruneNampower()
if HealBot_IsFighting then
HealBot_Action_PartyChanged()
end
HealBot_Delay_RecalcParty = 1;
end
+6 -3
View File
@@ -15,9 +15,12 @@ function HealBot_Range_Check(unit, range)
if ( unit == "player" ) then
return_val = 1;
elseif HealBot_Integrations_UnitXP_Active then
local dist = UnitXP("distanceBetween", "player", unit, "Gaussian")
if dist and dist <= range then
return_val = 1;
local inSight = UnitXP("inSight", "player", unit)
if inSight then
local dist = UnitXP("distanceBetween", "player", unit, "Gaussian")
if dist and dist <= range then
return_val = 1;
end
end
elseif ( UnitIsVisible(unit) == 1 ) then
local tx, ty = GetPlayerMapPosition(unit)
+1
View File
@@ -257,6 +257,7 @@ HealBot_ConfigDefaults = {
HideParty = 0,
HealBot_Integrations_UnitXP = 0,
HealBot_Integrations_Nampower = 0,
HealBot_Integrations_SuperWoW = 0,
};
HealBot_Config = {};
+75 -1
View File
@@ -15,9 +15,83 @@ function HealBot_Integrations_Toggle()
if HealBot_Config.HealBot_Integrations_Nampower == 1 then
HealBot_Integrations_Nampower_Active = true;
HealBot_AddDebug("nampower Integration: ENABLED");
-- Add Nampower specific initialization here later
if not HealBot_NampowerFrame then
HealBot_Nampower_Auras = {}
HealBot_NampowerFrame = CreateFrame("Frame")
HealBot_NampowerFrame:RegisterEvent("AURA_CAST_ON_SELF")
HealBot_NampowerFrame:RegisterEvent("AURA_CAST_ON_OTHER")
HealBot_NampowerFrame:SetScript("OnEvent", function()
if not HealBot_Integrations_Nampower_Active then return end
local spellID, caster, target, _, _, _, _, duration = arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8
if not caster or not target or duration <= 0 then return end
local spellName = GetSpellRecField(spellID, "name")
if not spellName then return end
if not HealBot_Nampower_Auras[target] then
HealBot_Nampower_Auras[target] = {}
end
local expirationTime = GetTime() + (duration / 1000)
HealBot_Nampower_Auras[target][spellName] = expirationTime
local unitID = HealBot_Model:GetUnitIDByName(target)
if unitID then
HealBot_OnEvent_UnitAura(nil, unitID)
end
end)
end
else
HealBot_Integrations_Nampower_Active = false;
HealBot_AddDebug("nampower Integration: DISABLED");
if HealBot_Nampower_Auras then
for k in pairs(HealBot_Nampower_Auras) do
HealBot_Nampower_Auras[k] = nil
end
end
end
function HealBot_Integrations_PruneNampower()
if not HealBot_Integrations_Nampower_Active or not HealBot_Nampower_Auras then return end
local currentTime = GetTime()
for targetName, auras in pairs(HealBot_Nampower_Auras) do
-- Check if target is still in the raid/party
if not HealBot_Model:GetUnitIDByName(targetName) then
HealBot_Nampower_Auras[targetName] = nil
else
-- Prune expired auras
local hasAuras = false
for spellName, expiration in pairs(auras) do
if currentTime > expiration then
auras[spellName] = nil
else
hasAuras = true
end
end
if not hasAuras then
HealBot_Nampower_Auras[targetName] = nil
end
end
end
end
-- SuperWoW
if HealBot_Config.HealBot_Integrations_SuperWoW == 1 and UnitExists ~= nil then
-- We can check if GetUnitGUID exists as a quick SuperWoW test, or UnitExists returns 2 args
-- Actually SuperWoW adds SpellInfo, or we can just rely on GetUnitGUID if it exists in the environment
if GetUnitGUID or (type(UnitExists) == "function") then
-- If the client actually supports GUID tracking via SuperWoW (or a similar mod)
HealBot_Integrations_SuperWoW_Active = true;
HealBot_AddDebug("SuperWoW Integration: ENABLED");
else
HealBot_Integrations_SuperWoW_Active = false;
HealBot_AddDebug("SuperWoW Integration: DISABLED (Mod Not Found)");
end
else
HealBot_Integrations_SuperWoW_Active = false;
HealBot_AddDebug("SuperWoW Integration: DISABLED");
end
end
+93 -2
View File
@@ -35,7 +35,11 @@ HealBot_Model = {
partyMembers = {},
raidMembers = {},
playerPet = nil,
target = nil
target = nil,
-- Integration maps
unitGUIDs = {}, -- unit -> GUID
guidUnits = {} -- GUID -> unit
}
--------------------------------------------------------------------------------
@@ -131,18 +135,105 @@ function HealBot_Model:UpdateUnitIdentity(unit)
if not self.units[unit] then return false end
local oldName = self.units[unit].name
local oldEnglishClass = self.units[unit].englishClass
local name = UnitName(unit)
local _, englishClass = UnitClass(unit)
if oldName ~= name then
if oldName ~= name or oldEnglishClass ~= englishClass then
self.units[unit].name = name
self.units[unit].englishClass = englishClass
self.units[unit].class = UnitClass(unit)
if HealBot_Integrations_SuperWoW_Active and GetUnitGUID then
local guid = GetUnitGUID(unit)
if guid then
self.unitGUIDs[unit] = guid
self.guidUnits[guid] = unit
end
end
return true -- Identity changed
end
return false
end
function HealBot_Model:GetUnitByGUID(guid)
if not guid then return nil end
return self.guidUnits[guid]
end
function HealBot_Model:GetUnitIDByName(name)
if not name then return nil end
for unit, data in pairs(self.units) do
if data.name == name then return unit end
end
return nil
end
function HealBot_Model:PreserveStateByGUID()
if not HealBot_Integrations_SuperWoW_Active or not GetUnitGUID then return end
local oldGUIDs = {}
for unit, guid in pairs(self.unitGUIDs) do
oldGUIDs[unit] = guid
end
local newUnitForGUID = {}
-- Scan the new roster
for _, unit in ipairs(self.partyMembers) do
local guid = GetUnitGUID(unit)
if guid then
newUnitForGUID[guid] = unit
self.unitGUIDs[unit] = guid
self.guidUnits[guid] = unit
end
end
for _, unit in ipairs(self.raidMembers) do
local guid = GetUnitGUID(unit)
if guid then
newUnitForGUID[guid] = unit
self.unitGUIDs[unit] = guid
self.guidUnits[guid] = unit
end
end
local stateSwaps = {}
local iconSwaps = {}
local missingBuffSwaps = {}
local debuffSwaps = {}
for oldUnit, guid in pairs(oldGUIDs) do
local newUnit = newUnitForGUID[guid]
if newUnit and newUnit ~= oldUnit then
stateSwaps[newUnit] = self.units[oldUnit]
-- Preserve external global tables if they exist
if HealBot_UnitIcons and HealBot_UnitIcons[oldUnit] then
iconSwaps[newUnit] = HealBot_UnitIcons[oldUnit]
end
if HealBot_MissingBuffs and HealBot_MissingBuffs[oldUnit] ~= nil then
missingBuffSwaps[newUnit] = HealBot_MissingBuffs[oldUnit]
end
if HealBot_UnitDebuff and HealBot_UnitDebuff[oldUnit] ~= nil then
debuffSwaps[newUnit] = HealBot_UnitDebuff[oldUnit]
end
end
end
for targetUnit, stateData in pairs(stateSwaps) do
self.units[targetUnit] = stateData
if HealBot_UnitIcons then
HealBot_UnitIcons[targetUnit] = iconSwaps[targetUnit]
end
if HealBot_MissingBuffs then
HealBot_MissingBuffs[targetUnit] = missingBuffSwaps[targetUnit]
end
if HealBot_UnitDebuff then
HealBot_UnitDebuff[targetUnit] = debuffSwaps[targetUnit]
end
end
end
-- Updates health/maxHealth values. Returns true if changed.
function HealBot_Model:UpdateUnitHealth(unit)
if not self.units[unit] then return false end
+1
View File
@@ -1,4 +1,5 @@
function HealBot_Options_Integrations_OnShow(this)
HealBot_Options_Integrations_UnitXP:SetChecked(HealBot_Config.HealBot_Integrations_UnitXP);
HealBot_Options_Integrations_Nampower:SetChecked(HealBot_Config.HealBot_Integrations_Nampower);
HealBot_Options_Integrations_SuperWoW:SetChecked(HealBot_Config.HealBot_Integrations_SuperWoW);
end
+19
View File
@@ -42,6 +42,25 @@
</Scripts>
</CheckButton>
<CheckButton name="HealBot_Options_Integrations_SuperWoW" inherits="OptionsCheckButtonTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="HealBot_Options_Integrations_Nampower" relativePoint="BOTTOMLEFT">
<Offset>
<AbsDimension x="0" y="5"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnLoad>
getglobal(this:GetName().."Text"):SetText("Enable SuperWoW Integration (GUID Tracking)");
</OnLoad>
<OnClick>
HealBot_Config.HealBot_Integrations_SuperWoW = this:GetChecked() and 1 or 0;
HealBot_Integrations_Toggle();
</OnClick>
</Scripts>
</CheckButton>
</Frames>
<Scripts>
<OnShow>
+8 -3
View File
@@ -39,8 +39,7 @@ Default installation path: `C:\Program Files\World of Warcraft\Interface\AddOns\
* **Highly Customizable Skins:** Fully configure dimensions (width, height), row spacing, column layouts, custom textures, opacity, class-colored frames, and outline of fonts.
### To be implemented
- **GUID-based frame mapping:** Migrate internal state to use lightweight GUID tracking to resolve bugs when targets switch or duplicate names appear (e.g., enemy mobs, warlock pets).
- **Mod Integration Optimization:** Add conditional SuperWoW/UnitXP SP3 integration to reduce GC spikes and improve frame rendering accuracy.
- **Strategy Pattern / Code Tree Splits:** Migrate heavy mod integrations (like Nampower aura tracking and SuperWoW UI rendering) into isolated code trees (e.g., `HealBot_Model_SuperWoW.lua`). This will allow dynamic overwriting of global functions at startup, eliminating the CPU overhead of running `if integration then` branch checks inside high-frequency update loops on Vanilla clients.
### Known issues
@@ -50,8 +49,14 @@ Default installation path: `C:\Program Files\World of Warcraft\Interface\AddOns\
### Change Log
**v1.7.0**
* **External Addon Integrations** - Added a new 'Extras' tab in Options to optionally enable integrations with `UnitXP_SP3` (for ultra-precise 3D range and Line of Sight checks) and `nampower` (for accurate real-time heal/buff tracking).
* **Integrations UI** - Added a new 'Extras' tab in the Options menu to easily toggle external mod integrations.
* **UnitXP_SP3 Integration** - Added optional support for UnitXP's API to provide ultra-precise 3D range finding and strict Line of Sight (LoS) checks. This completely bypasses the limitations of Vanilla's 2D map coordinate distance checks.
* **Nampower Integration** - Implemented background aura tracking to map explicit HoT expiration timestamps directly from nampower. This allows for accurate real-time heal and buff tracking instead of estimating based on cast times.
* **SuperWoW Integration** - Added robust GUID-based state tracking leveraging SuperWoW's enhanced API. This tracks players by their unique IDs rather than volatile unit strings.
* **UI Layout** - Widened the Options UI and neatly centered elements to accommodate the new integrations tab.
* **Bug Fix - Class Colors** - Fixed a bug where class colors failed to apply to new units due to a delayed server response.
* **Bug Fix - Combat Updates** - Fixed an issue where new party members joining mid-combat failed to append to the grid without dropping combat.
* **Bug Fix - Target Swaps** - Implemented optional SuperWoW GUID-based state preservation to prevent UI tracking bugs when group members are rearranged during combat.
**v1.6.3**
* **Hotfix string splitter** - added falback for string splitter if the the string is empty or nil.