From b0a0d88a7b608f11ea2fa93e31a5bc295cc79bfd Mon Sep 17 00:00:00 2001 From: Meow <30401521+me0wg4ming@users.noreply.github.com> Date: Sat, 3 Jan 2026 12:33:23 +0100 Subject: [PATCH] performance update performance update --- libs/libcast.lua | 124 +++++++++++++++++++++++++++++++++++++------- libs/libpredict.lua | 77 ++++++--------------------- libs/librange.lua | 40 +++++++++----- 3 files changed, 151 insertions(+), 90 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 11cada49..d8fc6c0d 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -53,14 +53,50 @@ local scanner = libtipscan:GetScanner("libcast") local libcast = CreateFrame("Frame", "pfEnemyCast") local player = UnitName("player") -UnitChannelInfo = _G.UnitChannelInfo or function(unit) +-- Store original SuperWoW UnitChannelInfo if it exists +local SuperWoW_UnitChannelInfo = _G.UnitChannelInfo + +UnitChannelInfo = function(unit) -- convert to name if unitstring was given - unit = pfValidUnits[unit] and UnitName(unit) or unit + local unitName = pfValidUnits[unit] and UnitName(unit) or unit + + -- For player: ALWAYS use libcast.db because it handles channel updates correctly + local isPlayer = unit == "player" or unitName == player + + if isPlayer then + local cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill + local db = libcast.db[player] + if db and db.cast and db.start + db.casttime / 1000 > GetTime() then + if not db.channel then return end + cast = db.cast + nameSubtext = db.rank + text = "" + texture = db.icon + startTime = db.start * 1000 + endTime = startTime + db.casttime + isTradeSkill = nil + elseif db then + db.cast = nil + db.rank = nil + db.start = nil + db.casttime = nil + db.icon = nil + db.channel = nil + end + + return cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill + end + + -- For non-player units: use SuperWoW if available, otherwise use libcast.db + if SuperWoW_UnitChannelInfo then + return SuperWoW_UnitChannelInfo(unit) + end + + -- Fallback to libcast.db for non-player units local cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill - local db = libcast.db[unit] + local db = libcast.db[unitName] - -- clean legacy values if db and db.cast and db.start + db.casttime / 1000 > GetTime() then if not db.channel then return end cast = db.cast @@ -71,7 +107,6 @@ UnitChannelInfo = _G.UnitChannelInfo or function(unit) endTime = startTime + db.casttime isTradeSkill = nil elseif db then - -- remove cast action to the database db.cast = nil db.rank = nil db.start = nil @@ -83,14 +118,51 @@ UnitChannelInfo = _G.UnitChannelInfo or function(unit) return cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill end -UnitCastingInfo = _G.UnitCastingInfo or function(unit) +-- Store original SuperWoW UnitCastingInfo if it exists +local SuperWoW_UnitCastingInfo = _G.UnitCastingInfo + +UnitCastingInfo = function(unit) -- convert to name if unitstring was given - unit = pfValidUnits[unit] and UnitName(unit) or unit + local unitName = pfValidUnits[unit] and UnitName(unit) or unit + + -- For player: ALWAYS use libcast.db because it handles pushback correctly + -- SuperWoW's UnitCastingInfo doesn't track SPELLCAST_DELAYED events + local isPlayer = unit == "player" or unitName == player + + if isPlayer then + local cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill + local db = libcast.db[player] + if db and db.cast and db.start + db.casttime / 1000 > GetTime() then + if db.channel then return end + cast = db.cast + nameSubtext = db.rank or "" + text = "" + texture = db.icon + startTime = db.start * 1000 + endTime = startTime + db.casttime + isTradeSkill = nil + elseif db then + db.cast = nil + db.rank = nil + db.start = nil + db.casttime = nil + db.icon = nil + db.channel = nil + end + + return cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill + end + + -- For non-player units: use SuperWoW if available, otherwise use libcast.db + if SuperWoW_UnitCastingInfo then + return SuperWoW_UnitCastingInfo(unit) + end + + -- Fallback to libcast.db for non-player units local cast, nameSubtext, text, texture, startTime, endTime, isTradeSkill - local db = libcast.db[unit] + local db = libcast.db[unitName] - -- clean legacy values if db and db.cast and db.start + db.casttime / 1000 > GetTime() then if db.channel then return end cast = db.cast @@ -101,7 +173,6 @@ UnitCastingInfo = _G.UnitCastingInfo or function(unit) endTime = startTime + db.casttime isTradeSkill = nil elseif db then - -- remove cast action to the database db.cast = nil db.rank = nil db.start = nil @@ -182,17 +253,31 @@ libcast:RegisterEvent("SPELLCAST_CHANNEL_STOP") libcast:RegisterEvent("SPELLCAST_CHANNEL_UPDATE") local mob, spell, icon, _ + libcast:SetScript("OnEvent", function() -- Fill database with player casts if event == "SPELLCAST_START" then icon = L["spells"][arg1] and L["spells"][arg1].icon and string.format("%s%s", "Interface\\Icons\\", L["spells"][arg1].icon) or lastcasttex - -- add cast action to the database - this.db[player].cast = arg1 - this.db[player].rank = lastrank - this.db[player].start = GetTime() - this.db[player].casttime = arg2 - this.db[player].icon = icon - this.db[player].channel = nil + + -- Check if SuperWoW already set the cast data (with correct haste-adjusted casttime) + -- If so, only update icon if needed, don't overwrite casttime + local superWowAlreadySet = this.db[player].cast == arg1 and this.db[player].casttime and this.db[player].casttime > 0 + + if superWowAlreadySet then + -- SuperWoW already set correct casttime, only update icon if better + if icon and not this.db[player].icon then + this.db[player].icon = icon + end + else + -- No SuperWoW data, use SPELLCAST_START data + this.db[player].cast = arg1 + this.db[player].rank = lastrank + this.db[player].start = GetTime() + this.db[player].casttime = arg2 + this.db[player].icon = icon + this.db[player].channel = nil + end + if not L["spells"][arg1] or not L["spells"][arg1].icon or not L["spells"][arg1].t then L["spells"][arg1] = L["spells"][arg1] or { } L["spells"][arg1].icon = L["spells"][arg1].icon or icon @@ -214,7 +299,9 @@ libcast:SetScript("OnEvent", function() end elseif event == "SPELLCAST_DELAYED" then if this.db[player].cast then - this.db[player].start = this.db[player].start + arg1/1000 + -- Pushback: increase casttime instead of shifting start + -- arg1 is the delay amount in milliseconds + this.db[player].casttime = this.db[player].casttime + arg1 end elseif event == "SPELLCAST_CHANNEL_START" then -- add cast action to the database @@ -224,6 +311,7 @@ libcast:SetScript("OnEvent", function() this.db[player].casttime = arg1 this.db[player].icon = L["spells"][arg2] and L["spells"][arg2].icon and string.format("%s%s", "Interface\\Icons\\", L["spells"][arg2].icon) or lastcasttex this.db[player].channel = true + lastcasttex, lastrank = nil, nil elseif event == "SPELLCAST_CHANNEL_STOP" then if this.db[player] and this.db[player].channel then diff --git a/libs/libpredict.lua b/libs/libpredict.lua index 77701f0b..83698369 100644 --- a/libs/libpredict.lua +++ b/libs/libpredict.lua @@ -9,10 +9,9 @@ setfenv(1, pfUI:GetEnvironment()) -- UnitGetIncomingHeals(unit) -- UnitHasIncomingResurrection(unit) -- --- The library is able to receive and send compatible messages to HealComm (vanilla) --- and HealComm (tbc) including the ressurections of both versions. It has an option --- to disable the sending of those messages in case one of the mentioned libraries --- is already active. +-- The library is able to receive and send compatible messages to HealComm +-- including resurrections. It has an option to disable the sending of those +-- messages in case HealComm is already active. -- return instantly when another libpredict is already active if pfUI.api.libpredict then return end @@ -457,15 +456,6 @@ libpredict.sender:SetScript("OnUpdate", function() end end) --- tbc -libpredict.sender:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_START") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_STOP") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_FAILED") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED") -libpredict.sender:RegisterEvent("UNIT_SPELLCAST_SENT") - --- vanilla libpredict.sender:RegisterEvent("CHAT_MSG_SPELL_SELF_BUFF") libpredict.sender:RegisterEvent("SPELLCAST_START") libpredict.sender:RegisterEvent("SPELLCAST_STOP") @@ -502,24 +492,9 @@ libpredict.sender:SetScript("OnEvent", function() if spell == spell_queue[1] then UpdateCache(spell_queue[2], heal, true) end return end - elseif event == "COMBAT_LOG_EVENT_UNFILTERED" and arg2 == "SPELL_HEAL" and arg4 == player then -- tbc - local spell, heal, crit = arg10, arg12, arg13 - if spell and heal and crit then - if spell == spell_queue[1] then UpdateCache(spell_queue[2], heal, true) end - elseif spell and heal then - if spell == spell_queue[1] then UpdateCache(spell_queue[2], heal) end - end - elseif event == "UNIT_SPELLCAST_SENT" and arg4 then -- fix tbc mouseover macros - senttarget = arg4 - elseif strfind(event, "SPELLCAST_START", 1) then + elseif event == "SPELLCAST_START" then local spell, time = arg1, arg2 - if strfind(event, "UNIT_", 1) then -- tbc - if arg1 ~= "player" then return end - local spellname, _, _, _, starttime, endtime = UnitCastingInfo("player") - spell, time = spellname, endtime - starttime - end - if spell_queue[1] == spell and cache[spell_queue[2]] then local sender = player local target = senttarget or spell_queue[3] @@ -540,22 +515,14 @@ libpredict.sender:SetScript("OnEvent", function() for i=1,4 do if CheckInteractDistance("party"..i, 4) then libpredict:Heal(player, UnitName("party"..i), amount, casttime) - if pfUI.client < 20000 then -- vanilla - libpredict.sender:SendHealCommMsg("Heal/" .. UnitName("party"..i) .. "/" .. amount .. "/" .. casttime .. "/") - else -- tbc - libpredict.sender:SendHealCommMsg(string.format("002%05d%s", math.min(amount, 99999), UnitName("party"..i))) - end + libpredict.sender:SendHealCommMsg("Heal/" .. UnitName("party"..i) .. "/" .. amount .. "/" .. casttime .. "/") libpredict.sender.healing = true end end end libpredict:Heal(player, target, amount, casttime) - if pfUI.client < 20000 then -- vanilla - libpredict.sender:SendHealCommMsg("Heal/" .. target .. "/" .. amount .. "/" .. casttime .. "/") - else -- tbc - libpredict.sender:SendHealCommMsg(string.format("002%05d%s", math.min(amount, 99999), target)) - end + libpredict.sender:SendHealCommMsg("Heal/" .. target .. "/" .. amount .. "/" .. casttime .. "/") libpredict.sender.healing = true elseif spell_queue[1] == spell and L["resurrections"][spell] then @@ -565,15 +532,10 @@ libpredict.sender:SetScript("OnEvent", function() libpredict.sender:SendResCommMsg("RES " .. target) libpredict.sender.resurrecting = true end - elseif strfind(event, "SPELLCAST_FAILED", 1) or strfind(event, "SPELLCAST_INTERRUPTED", 1) then - if strfind(event, "UNIT_", 1) and arg1 ~= "player" then return end + elseif event == "SPELLCAST_FAILED" or event == "SPELLCAST_INTERRUPTED" then if libpredict.sender.healing then libpredict:HealStop(player) - if pfUI.client < 20000 then -- vanilla - libpredict.sender:SendHealCommMsg("HealStop") - else -- tbc - libpredict.sender:SendHealCommMsg("001F") - end + libpredict.sender:SendHealCommMsg("HealStop") libpredict.sender.healing = nil elseif libpredict.sender.resurrecting then local target = senttarget or spell_queue[3] @@ -590,21 +552,16 @@ libpredict.sender:SetScript("OnEvent", function() libpredict:HealDelay(player, arg1) libpredict.sender:SendHealCommMsg("Healdelay/" .. arg1 .. "/") end - elseif strfind(event, "SPELLCAST_STOP", 1) then - if strfind(event, "UNIT_", 1) and arg1 ~= "player" then return end + elseif event == "SPELLCAST_STOP" then libpredict:HealStop(player) - if pfUI.client < 20000 then -- vanilla - if spell_queue[1] == REJUVENATION then - libpredict:Hot(player, spell_queue[3], "Reju", rejuvDuration) - libpredict.sender:SendHealCommMsg("Reju/"..spell_queue[3].."/"..rejuvDuration.."/") - elseif spell_queue[1] == RENEW then - libpredict:Hot(player, spell_queue[3], "Renew", renewDuration) - libpredict.sender:SendHealCommMsg("Renew/"..spell_queue[3].."/"..renewDuration.."/") - elseif spell_queue[1] == REGROWTH then - this.regrowth_timer = GetTime() + 0.1 - end - else -- tbc - --todo + if spell_queue[1] == REJUVENATION then + libpredict:Hot(player, spell_queue[3], "Reju", rejuvDuration) + libpredict.sender:SendHealCommMsg("Reju/"..spell_queue[3].."/"..rejuvDuration.."/") + elseif spell_queue[1] == RENEW then + libpredict:Hot(player, spell_queue[3], "Renew", renewDuration) + libpredict.sender:SendHealCommMsg("Renew/"..spell_queue[3].."/"..renewDuration.."/") + elseif spell_queue[1] == REGROWTH then + this.regrowth_timer = GetTime() + 0.1 end end end) diff --git a/libs/librange.lua b/libs/librange.lua index c6e9c1a2..05c06743 100644 --- a/libs/librange.lua +++ b/libs/librange.lua @@ -39,10 +39,10 @@ local spells = { }, } --- use native IsSpellInRange checker for tbc and skip --- the whole targeting approach that is required for vanilla -if pfUI.expansion == "tbc" then - local spell +-- Use Nampower's IsSpellInRange if available (vanilla only) +-- This provides more accurate range checking without needing to find spell slots +local nampower_spell +if GetNampowerVersion then librange:RegisterEvent("LEARNED_SPELL_IN_TAB") librange:RegisterEvent("PLAYER_ENTERING_WORLD") librange:SetScript("OnEvent", function() @@ -53,12 +53,14 @@ if pfUI.expansion == "tbc" then local _, _, offset, num = GetSpellTabInfo(i) for id = offset + 1, offset + num do local name, rank = GetSpellName(id, BOOKTYPE_SPELL) - local texture = GetSpellTexture(name) + local texture = GetSpellTexture(id, BOOKTYPE_SPELL) - for _, tex in pairs(spells[class]) do - if tex == texture then - spell = name - return + if texture then + for _, tex in pairs(spells[class]) do + if tex == texture then + nampower_spell = name + return + end end end end @@ -66,8 +68,12 @@ if pfUI.expansion == "tbc" then end) function librange:UnitInSpellRange(unit) - if not spell then return nil end - return IsSpellInRange(spell, unit) == 1 and true or nil + if not nampower_spell then return nil end + -- Nampower's IsSpellInRange returns 1 if in range, 0 if not, -1 if invalid + local result = IsSpellInRange(nampower_spell, unit) + if result == 1 then return 1 + elseif result == 0 then return nil + else return nil end end -- add librange to pfUI API @@ -161,7 +167,17 @@ librange:SetScript("OnUpdate", function() if this.id <= numunits and librange.slot then local unit = units[this.id] if not UnitIsUnit("target", unit) then - -- try to read distance via superwow first + -- Try UnitXP_SP3 first (most accurate distance measurement) + local unitxp_success, unitxp_distance = pcall(function() + return UnitXP("distanceBetween", "player", unit) + end) + if unitxp_success and unitxp_distance then + unitdata[unit] = unitxp_distance < 45 and 1 or 0 + this.id = this.id + 1 + return + end + + -- try to read distance via superwow second if superwow_active then local x1, y1, z1 = UnitPosition("player") local x2, y2, z2 = UnitPosition(unit)