Merge pull request #21 from Bluewhale1337/dev

Dev
This commit is contained in:
Bluewhale1337
2026-09-24 22:34:31 +02:00
committed by GitHub
9 changed files with 140 additions and 43 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
## Interface: 11200
## Title: HealBotBlue
## Version: 1.7.2
## Version: 1.7.3
## Author: Bluewhale
## Notes: Raidframe replacement for healing, decursing, resource tracking and buffing with optional support for SuperWow, ClassicAPI, UnitXP_SP3 and Nampower.
## SavedVariablesPerCharacter: HealBot_Config
+4 -2
View File
@@ -136,9 +136,10 @@ end
-- HealBot_SplitString: Internal utility: HealBot_SplitString
function HealBot_SplitString(str, delimiter)
local result = {}
local result = HealBot_GetTable()
if not delimiter or delimiter == "" then
return {str}
table.insert(result, str)
return result
end
local start_pos = 1
while true do
@@ -160,6 +161,7 @@ function HealBot_RunMacroText(body)
ChatFrameEditBox:SetText(commands[i])
ChatEdit_SendText(ChatFrameEditBox)
end
HealBot_ReleaseTable(commands)
end
-- HealBot_RunMacro: Internal utility: HealBot_RunMacro
+8 -2
View File
@@ -41,6 +41,7 @@ function HealBot_CheckShamanWeaponBuff(spellName)
if not firstWord then return false end
HealBot_ScanTooltip:SetOwner(UIParent, "ANCHOR_NONE")
if not HealBot_ScanTooltip_Lines then HealBot_ScanTooltip_Lines = {} end
local slots = HealBot_GetTable()
if hasMainHandEnchant then table.insert(slots, 16) end
if hasOffHandEnchant then table.insert(slots, 17) end
@@ -49,7 +50,11 @@ function HealBot_CheckShamanWeaponBuff(spellName)
HealBot_ScanTooltip:ClearLines()
HealBot_ScanTooltip:SetInventoryItem("player", slot)
for i = 1, HealBot_ScanTooltip:NumLines() do
local textObj = getglobal("HealBot_ScanTooltipTextLeft" .. i)
local textObj = HealBot_ScanTooltip_Lines[i]
if not textObj then
textObj = getglobal("HealBot_ScanTooltipTextLeft" .. i)
HealBot_ScanTooltip_Lines[i] = textObj
end
if textObj then
local text = textObj:GetText()
if text and string.find(text, firstWord) then
@@ -184,7 +189,7 @@ function HealBot_OnEvent_UnitAura(this, unit)
local iconCount = 0
local i = 1;
HealBot_UnitDebuff[unit] = nil;
local trackedTextures = {}
local trackedTextures = HealBot_GetTable()
while true do
local debuff, tmp, debuff_type = UnitDebuff(unit, i, 1)
@@ -301,5 +306,6 @@ function HealBot_OnEvent_UnitAura(this, unit)
-- Defer UI updates
HealBot_View_DirtyUnits[unit] = true
HealBot_ReleaseTable(trackedTextures)
end
end
+6 -6
View File
@@ -69,11 +69,11 @@ function HealBot_OnUpdate(this, arg1)
local pending = HealBot_TargetRestorePending;
HealBot_TargetRestorePending = nil;
HealBot_TargetRestoreTimer = 0;
if pending.type == "enemy" then
if pending == "enemy" then
TargetLastEnemy();
elseif pending.type == "friend" then
elseif pending == "friend" then
TargetLastTarget();
elseif pending.type == "clear" then
elseif pending == "clear" then
ClearTarget();
end
end
@@ -112,11 +112,11 @@ function HealBot_OnUpdate(this, arg1)
-- Restore target logic
if pendingCast.targetEnemy then
HealBot_TargetRestorePending = { type = "enemy" }
HealBot_TargetRestorePending = "enemy"
elseif pendingCast.oldTarget and pendingCast.oldTarget ~= UnitName(pendingCast.target) then
HealBot_TargetRestorePending = { type = "friend" }
HealBot_TargetRestorePending = "friend"
elseif not pendingCast.oldTarget then
HealBot_TargetRestorePending = { type = "clear" }
HealBot_TargetRestorePending = "clear"
end
HealBot_TargetRestoreTimer = 0
end
+102 -24
View File
@@ -3,6 +3,7 @@
HealBot_CastingSpell = nil;
HealBot_CastingTarget = nil;
HealBot_CastingGroupMembers = nil;
HealBot_TargetRestorePending = nil;
HealBot_TargetRestoreTimer = 0;
@@ -158,13 +159,52 @@ function HealBot_Process_HealValue(spell, target)
end
local uname = UnitName(target)
if uname then
HealBot_SendAddonMessage(HEALBOT_ADDON_ID, ">> " .. uname .. " <<=>> " .. HealBot_HealValue .. " << ");
HealBot_SendAddonMessage("HealComm", "Heal/" .. uname .. "/" .. HealBot_HealValue .. "/1500/");
if not HealBot_HealsIn[uname] then
HealBot_HealsIn[uname] = 0;
if not HealBot_CastingGroupMembers then HealBot_CastingGroupMembers = {} end
for i=1, table.getn(HealBot_CastingGroupMembers) do HealBot_CastingGroupMembers[i] = nil end
table.setn(HealBot_CastingGroupMembers, 0)
if HEALBOT_PRAYER_OF_HEALING and string.find(spell, HEALBOT_PRAYER_OF_HEALING) then
if GetNumRaidMembers() > 0 then
local targetGroup = 0
for i = 1, GetNumRaidMembers() do
local name, _, subgroup = GetRaidRosterInfo(i)
if name == uname then targetGroup = subgroup; break; end
end
if targetGroup > 0 then
for i = 1, GetNumRaidMembers() do
local name, _, subgroup = GetRaidRosterInfo(i)
if subgroup == targetGroup and name then table.insert(HealBot_CastingGroupMembers, name); end
end
end
else
table.insert(HealBot_CastingGroupMembers, UnitName("player"))
for i = 1, GetNumPartyMembers() do
if UnitName("party"..i) then table.insert(HealBot_CastingGroupMembers, UnitName("party"..i)); end
end
end
end
if table.getn(HealBot_CastingGroupMembers) == 0 then
table.insert(HealBot_CastingGroupMembers, uname)
end
if table.getn(HealBot_CastingGroupMembers) > 1 then
local commsStr = "GrpHeal/" .. HealBot_HealValue .. "/1500/"
for _, memberName in ipairs(HealBot_CastingGroupMembers) do
commsStr = commsStr .. memberName .. "/"
end
HealBot_SendAddonMessage("HealComm", commsStr)
for _, memberName in ipairs(HealBot_CastingGroupMembers) do
HealBot_SendAddonMessage(HEALBOT_ADDON_ID, ">> " .. memberName .. " <<=>> " .. HealBot_HealValue .. " << ")
if not HealBot_HealsIn[memberName] then HealBot_HealsIn[memberName] = 0 end
HealBot_HealsIn[memberName] = HealBot_HealsIn[memberName] + HealBot_HealValue
HealBot_RecalcHeals(HealBot_FindUnitID(memberName))
end
else
HealBot_SendAddonMessage("HealComm", "Heal/" .. uname .. "/" .. HealBot_HealValue .. "/1500/")
HealBot_SendAddonMessage(HEALBOT_ADDON_ID, ">> " .. uname .. " <<=>> " .. HealBot_HealValue .. " << ")
if not HealBot_HealsIn[uname] then HealBot_HealsIn[uname] = 0 end
HealBot_HealsIn[uname] = HealBot_HealsIn[uname] + HealBot_HealValue
HealBot_RecalcHeals(HealBot_FindUnitID(uname))
end
HealBot_HealsIn[uname] = HealBot_HealsIn[uname] + HealBot_HealValue;
HealBot_RecalcHeals(HealBot_FindUnitID(uname));
end
end
end
@@ -217,14 +257,24 @@ function HealBot_StopCasting()
if HealBot_HealValue > 0 then
local uname = UnitName(HealBot_CastingTarget)
if uname then
HealBot_SendAddonMessage(HEALBOT_ADDON_ID, ">> " .. uname .. " <<=>> " .. 0 - HealBot_HealValue .. " << ");
HealBot_SendAddonMessage("HealComm", "Healstop");
if HealBot_HealsIn[uname] then
HealBot_HealsIn[uname] = HealBot_HealsIn[uname] - HealBot_HealValue;
if HealBot_HealsIn[uname] < 0 then
HealBot_HealsIn[uname] = 0;
end
HealBot_RecalcHeals(HealBot_FindUnitID(uname));
if HealBot_CastingGroupMembers and table.getn(HealBot_CastingGroupMembers) > 1 then
HealBot_SendAddonMessage("HealComm", "GrpHealstop");
for _, memberName in ipairs(HealBot_CastingGroupMembers) do
HealBot_SendAddonMessage(HEALBOT_ADDON_ID, ">> " .. memberName .. " <<=>> " .. 0 - HealBot_HealValue .. " << ")
if HealBot_HealsIn[memberName] then
HealBot_HealsIn[memberName] = HealBot_HealsIn[memberName] - HealBot_HealValue;
if HealBot_HealsIn[memberName] < 0 then HealBot_HealsIn[memberName] = 0; end
HealBot_RecalcHeals(HealBot_FindUnitID(memberName));
end
end
else
HealBot_SendAddonMessage("HealComm", "Healstop");
HealBot_SendAddonMessage(HEALBOT_ADDON_ID, ">> " .. uname .. " <<=>> " .. 0 - HealBot_HealValue .. " << ");
if HealBot_HealsIn[uname] then
HealBot_HealsIn[uname] = HealBot_HealsIn[uname] - HealBot_HealValue;
if HealBot_HealsIn[uname] < 0 then HealBot_HealsIn[uname] = 0; end
HealBot_RecalcHeals(HealBot_FindUnitID(uname));
end
end
end
HealBot_HealValue = 0;
@@ -237,7 +287,7 @@ function HealBot_StopCasting()
local ag = HealBot_Config.babortcolg[HealBot_Config.Current_Skin] or 0.1;
local ab = HealBot_Config.babortcolb[HealBot_Config.Current_Skin] or 0.5;
local aa = HealBot_Config.babortcola[HealBot_Config.Current_Skin] or 1;
bar.txt = getglobal(bar:GetName() .. "_text");
if not bar.txt then bar.txt = getglobal(bar:GetName() .. "_text") end
bar:SetStatusBarColor(ar, ag, ab, 0);
local sr = HealBot_Config.btextdisbledcolr[HealBot_Config.Current_Skin];
local sg = HealBot_Config.btextdisbledcolg[HealBot_Config.Current_Skin];
@@ -303,7 +353,7 @@ function HealBot_CheckCasting(unit)
local sg = HealBot_Config.btextenabledcolg[HealBot_Config.Current_Skin];
local sb = HealBot_Config.btextenabledcolb[HealBot_Config.Current_Skin];
local sa = HealBot_Config.btextenabledcola[HealBot_Config.Current_Skin];
bar.txt = getglobal(bar:GetName() .. "_text");
if not bar.txt then bar.txt = getglobal(bar:GetName() .. "_text") end
bar.txt:SetTextColor(sr, sg, sb, sa);
end
end
@@ -328,7 +378,15 @@ function HealBot_CastSpellOnFriend(spell, target)
if formCancelled then
-- ALWAYS put the cast into the Pending queue so the OnUpdate loop can wait for the server
-- to process the unshift before attempting the cast, otherwise we get "You are in shapeshift form".
HealBot_PendingShapeshiftCast = { spell = spell, target = target, targetEnemy = targetEnemy, oldTarget = oldTarget, fireTime = GetTime() + 0.05, expires = GetTime() + 2.0 }
if not HealBot_PendingShapeshiftCast then HealBot_PendingShapeshiftCast = {} end
HealBot_PendingShapeshiftCast.spell = spell
HealBot_PendingShapeshiftCast.target = target
HealBot_PendingShapeshiftCast.targetEnemy = targetEnemy
HealBot_PendingShapeshiftCast.oldTarget = oldTarget
HealBot_PendingShapeshiftCast.fireTime = GetTime() + 0.05
HealBot_PendingShapeshiftCast.expires = GetTime() + 2.0
HealBot_PendingShapeshiftCast.started = nil
HealBot_PendingShapeshiftCast.nextSpam = nil
return;
end
@@ -339,11 +397,11 @@ function HealBot_CastSpellOnFriend(spell, target)
HealBot_StartCasting(spell, target, "direct");
if targetEnemy then
HealBot_TargetRestorePending = { type = "enemy" };
HealBot_TargetRestorePending = "enemy";
elseif oldTarget and oldTarget ~= UnitName(target) then
HealBot_TargetRestorePending = { type = "friend" };
HealBot_TargetRestorePending = "friend";
elseif not oldTarget then
HealBot_TargetRestorePending = { type = "clear" };
HealBot_TargetRestorePending = "clear";
end
HealBot_TargetRestoreTimer = 0;
end
@@ -472,7 +530,7 @@ function HealBot_FindHealSpells()
end
end);
local items = {};
local items = HealBot_GetTable();
for bag = 0, NUM_BAG_FRAMES do
for slot = 1, GetContainerNumSlots(bag) do
local item = HealBot_GetItemName(bag, slot);
@@ -498,6 +556,7 @@ function HealBot_FindHealSpells()
HealBot_Heals["raidpet" .. i] = HealBot_Heals.party;
end
HealBot_ReleaseTable(items);
if HealBot_CalcEquipBonus then
HealBot_AddDebug("...Done Equip Bonus:" .. RealHealing);
end
@@ -568,7 +627,15 @@ end
-- HealBot_RecalcHeals: Flags unit for visual refresh.
function HealBot_RecalcHeals(unit)
HealBot_Action_Refresh(unit);
if unit then
HealBot_View_DirtyUnits[unit] = true;
else
if HealBot_Action_UnitButtons then
for u, _ in pairs(HealBot_Action_UnitButtons) do
HealBot_View_DirtyUnits[u] = true;
end
end
end
end
-- HealBot_RecalcParty: Triggers group layout rebuild.
@@ -673,8 +740,15 @@ function HealBot_InitGetSpellData(spell, id, class)
_cast = 0;
line = nil;
if not HealBot_ScanTooltip_Lines_Left then HealBot_ScanTooltip_Lines_Left = {} end
if not HealBot_ScanTooltip_Lines_Right then HealBot_ScanTooltip_Lines_Right = {} end
for lineNum = 2, 6 do
local lText = getglobal("HealBot_ScanTooltipTextLeft"..lineNum);
local lText = HealBot_ScanTooltip_Lines_Left[lineNum];
if not lText then
lText = getglobal("HealBot_ScanTooltipTextLeft"..lineNum);
HealBot_ScanTooltip_Lines_Left[lineNum] = lText;
end
if lText and lText:IsVisible() and lText:GetText() then
local txt = lText:GetText();
local t1, t2, match;
@@ -698,7 +772,11 @@ function HealBot_InitGetSpellData(spell, id, class)
end
end
local rText = getglobal("HealBot_ScanTooltipTextRight"..lineNum);
local rText = HealBot_ScanTooltip_Lines_Right[lineNum];
if not rText then
rText = getglobal("HealBot_ScanTooltipTextRight"..lineNum);
HealBot_ScanTooltip_Lines_Right[lineNum] = rText;
end
if rText and rText:IsVisible() and rText:GetText() then
local txt = rText:GetText();
local t1, t2, match;
+5 -2
View File
@@ -44,7 +44,7 @@ function HealBot_Integrations_Toggle()
if not spellName then return end
if not HealBot_Nampower_Auras[target] then
HealBot_Nampower_Auras[target] = {}
HealBot_Nampower_Auras[target] = HealBot_GetTable()
end
local expirationTime = GetTime() + (duration / 1000)
@@ -61,7 +61,8 @@ function HealBot_Integrations_Toggle()
HealBot_Integrations_Nampower_Active = false;
HealBot_AddDebug("nampower Integration: DISABLED");
if HealBot_Nampower_Auras then
for k in pairs(HealBot_Nampower_Auras) do
for k, v in pairs(HealBot_Nampower_Auras) do
HealBot_ReleaseTable(v)
HealBot_Nampower_Auras[k] = nil
end
end
@@ -76,6 +77,7 @@ function HealBot_Integrations_PruneNampower()
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_ReleaseTable(auras)
HealBot_Nampower_Auras[targetName] = nil
else
-- Prune expired auras
@@ -88,6 +90,7 @@ function HealBot_Integrations_PruneNampower()
end
end
if not hasAuras then
HealBot_ReleaseTable(auras)
HealBot_Nampower_Auras[targetName] = nil
end
end
+4 -3
View File
@@ -245,11 +245,12 @@ function HealBot_Model:PreserveStateByGUID()
for targetUnit, stateData in pairs(stateSwaps) do
-- Deep copy to prevent memory aliasing
if not self.units[targetUnit] then
self.units[targetUnit] = { icons = {} }
self.units[targetUnit] = HealBot_GetTable()
self.units[targetUnit].icons = HealBot_GetTable()
end
local targetIcons = self.units[targetUnit].icons
if not targetIcons then targetIcons = {} end
if not targetIcons then targetIcons = HealBot_GetTable() end
for k in pairs(targetIcons) do targetIcons[k] = nil end
for k in pairs(self.units[targetUnit]) do self.units[targetUnit][k] = nil end
@@ -262,7 +263,7 @@ function HealBot_Model:PreserveStateByGUID()
self.units[targetUnit].icons = targetIcons
if HealBot_UnitIcons and iconSwaps[targetUnit] then
if not HealBot_UnitIcons[targetUnit] then HealBot_UnitIcons[targetUnit] = {} end
if not HealBot_UnitIcons[targetUnit] then HealBot_UnitIcons[targetUnit] = HealBot_GetTable() end
for j=1, 10 do
HealBot_UnitIcons[targetUnit][j] = iconSwaps[targetUnit][j]
end
+6 -3
View File
@@ -857,8 +857,10 @@ function HealBot_Action_PartyChanged()
if i == last then break end
end
else
local petUnits = { "pet", "partypet1", "partypet2", "partypet3", "partypet4" };
for _, unit in ipairs(petUnits) do
if not HealBot_PetUnits then
HealBot_PetUnits = { "pet", "partypet1", "partypet2", "partypet3", "partypet4" };
end
for _, unit in ipairs(HealBot_PetUnits) do
if not HealBot_Action_UnitButtons[unit] and HealBot_MayHeal(unit) then
i = i + 1;
HealBot_Action_SetHealButton(i, unit);
@@ -1153,7 +1155,7 @@ end
function HealBot_Action_AppendNewUnits()
if not HealBot_Grid_LastI then return end
local unitsToCheck = {}
local unitsToCheck = HealBot_GetTable()
-- Gather units based on config, similar to PartyChanged
if HealBot_Config.GroupHeals == 1 then
@@ -1220,4 +1222,5 @@ function HealBot_Action_AppendNewUnits()
HealBot_Action_AppendUnit(unit)
end
end
HealBot_ReleaseTable(unitsToCheck)
end
+4
View File
@@ -49,6 +49,10 @@ Default installation path: `C:\Program Files\World of Warcraft\Interface\AddOns\
### Change Log
**v1.7.3**
* **Performance Fix - Table Pooling Part 2** - Fixed remaining un-pooled table allocations in layout updates, macro parsing, nampower integration, and aura tracking by utilizing HealBot_GetTable().
* **Performance Fix - HealComm Networking** - Fixed issue where incoming `HealComm` messages triggered synchronous UI redraws, causing massive lag in 40-man raids during combat. `HealBot_RecalcHeals` is now decoupled and deferred through the `HealBot_OnUpdate` dirty queue, allowing multiple network events to collapse into a single frame redraw.
**v1.7.2**
* **Performance Fix - Table Pooling** - Fixed massive Vanilla Lua 5.0 garbage collection memory leaks caused by unbounded table allocations in high-frequency update loops (e.g., `OnUpdate` and `PreserveStateByGUID`). Moved tables to file-local scope and implemented inline clearing.
* **Performance Fix - OOC Cleanup** - Added an out-of-combat garbage collection hook (`PLAYER_REGEN_ENABLED`) to purge disconnected senders from the `HealBot_IncomingHealers` global table, preventing memory bloat during prolonged play sessions.