From e21063388d1a5306cd6a3a9a95a5bf6f3f0161be Mon Sep 17 00:00:00 2001 From: Artur Morozov Date: Fri, 9 Feb 2024 19:52:55 +0300 Subject: [PATCH 01/70] mapcolors: rewrite module implementation --- api/config.lua | 1 + env/translations_deDE.lua | 1 + env/translations_enUS.lua | 1 + env/translations_esES.lua | 1 + env/translations_frFR.lua | 1 + env/translations_koKR.lua | 1 + env/translations_ruRU.lua | 1 + env/translations_zhCN.lua | 1 + env/translations_zhTW.lua | 1 + modules/gui.lua | 1 + modules/mapcolors.lua | 174 ++++++++++++++++++++------------------ 11 files changed, 104 insertions(+), 80 deletions(-) diff --git a/api/config.lua b/api/config.lua index 75b81acc6..42d540676 100644 --- a/api/config.lua +++ b/api/config.lua @@ -178,6 +178,7 @@ function pfUI:LoadConfig() pfUI:UpdateConfig("appearance", "worldmap", "mapreveal_color", ".4,.4,.4,1") pfUI:UpdateConfig("appearance", "worldmap", "mapexploration", "0") pfUI:UpdateConfig("appearance", "worldmap", "groupcircles", "3") + pfUI:UpdateConfig("appearance", "worldmap", "colornames", "1") pfUI:UpdateConfig("loot", nil, "autoresize", "1") pfUI:UpdateConfig("loot", nil, "autopickup", "1") diff --git a/env/translations_deDE.lua b/env/translations_deDE.lua index 01cd82a81..c841558f8 100644 --- a/env/translations_deDE.lua +++ b/env/translations_deDE.lua @@ -119,6 +119,7 @@ pfUI_translation["deDE"] = { ["Close"] = nil, ["Color Buff Stacks"] = nil, ["Color Debuff Stacks"] = nil, + ["Colorize player name on WorldMap and BattlefieldMinimap"] = nil, ["Colorize Unknown Classes"] = nil, ["Colors"] = nil, ["Combat"] = nil, diff --git a/env/translations_enUS.lua b/env/translations_enUS.lua index b1a5d49a8..2c9301ae8 100644 --- a/env/translations_enUS.lua +++ b/env/translations_enUS.lua @@ -119,6 +119,7 @@ pfUI_translation["enUS"] = { ["Close"] = nil, ["Color Buff Stacks"] = nil, ["Color Debuff Stacks"] = nil, + ["Colorize player name on WorldMap and BattlefieldMinimap"] = nil, ["Colorize Unknown Classes"] = nil, ["Colors"] = nil, ["Combat"] = nil, diff --git a/env/translations_esES.lua b/env/translations_esES.lua index 3f77b5163..bb4376092 100644 --- a/env/translations_esES.lua +++ b/env/translations_esES.lua @@ -119,6 +119,7 @@ pfUI_translation["esES"] = { ["Close"] = "Cerrar", ["Color Buff Stacks"] = "Colorear pilas de beneficios", ["Color Debuff Stacks"] = "Colorear pilas de perjuicios", + ["Colorize player name on WorldMap and BattlefieldMinimap"] = nil, ["Colorize Unknown Classes"] = "Colorear clases desconocidas", ["Colors"] = "Colores", ["Combat"] = "Combate", diff --git a/env/translations_frFR.lua b/env/translations_frFR.lua index 5f8727f16..6f9119b63 100644 --- a/env/translations_frFR.lua +++ b/env/translations_frFR.lua @@ -119,6 +119,7 @@ pfUI_translation["frFR"] = { ["Close"] = "Fermer", ["Color Buff Stacks"] = "Couleur des l'empilements des Améliorations", ["Color Debuff Stacks"] = "Couleur de l'empilements de Affaiblissements", + ["Colorize player name on WorldMap and BattlefieldMinimap"] = nil, ["Colorize Unknown Classes"] = "Colorie les classes inconnues", ["Colors"] = "Couleurs", ["Combat"] = "Combat", diff --git a/env/translations_koKR.lua b/env/translations_koKR.lua index 34e1fb93e..49564c911 100644 --- a/env/translations_koKR.lua +++ b/env/translations_koKR.lua @@ -119,6 +119,7 @@ pfUI_translation["koKR"] = { ["Close"] = "닫기", ["Color Buff Stacks"] = nil, ["Color Debuff Stacks"] = nil, + ["Colorize player name on WorldMap and BattlefieldMinimap"] = nil, ["Colorize Unknown Classes"] = nil, ["Colors"] = nil, ["Combat"] = "전투", diff --git a/env/translations_ruRU.lua b/env/translations_ruRU.lua index 2805eef3e..3ddaf79c7 100644 --- a/env/translations_ruRU.lua +++ b/env/translations_ruRU.lua @@ -119,6 +119,7 @@ pfUI_translation["ruRU"] = { ["Close"] = "Закрыть", ["Color Buff Stacks"] = "Цвет стаков баффа", ["Color Debuff Stacks"] = "Цвет стаков дебаффа", + ["Colorize player name on WorldMap and BattlefieldMinimap"] = "Раскрасить имена игроков на карте мира и миникарте поля боя", ["Colorize Unknown Classes"] = "Раскрасить неизвестные классы", ["Colors"] = "Цвета по умолчанию", ["Combat"] = "Бой", diff --git a/env/translations_zhCN.lua b/env/translations_zhCN.lua index 8bc2795a7..b461567e3 100644 --- a/env/translations_zhCN.lua +++ b/env/translations_zhCN.lua @@ -119,6 +119,7 @@ pfUI_translation["zhCN"] = { ["Close"] = "关闭", ["Color Buff Stacks"] = "Buff堆叠颜色", ["Color Debuff Stacks"] = "Debuff堆叠颜色", + ["Colorize player name on WorldMap and BattlefieldMinimap"] = nil, ["Colorize Unknown Classes"] = "有色未知职业", ["Colors"] = "颜色", ["Combat"] = "战斗报警", diff --git a/env/translations_zhTW.lua b/env/translations_zhTW.lua index e8fa61616..d6c43de77 100644 --- a/env/translations_zhTW.lua +++ b/env/translations_zhTW.lua @@ -119,6 +119,7 @@ pfUI_translation["zhTW"] = { ["Close"] = "關閉", ["Color Buff Stacks"] = nil, ["Color Debuff Stacks"] = nil, + ["Colorize player name on WorldMap and BattlefieldMinimap"] = nil, ["Colorize Unknown Classes"] = "未知職業色彩", ["Colors"] = nil, ["Combat"] = "戰鬥報警", diff --git a/modules/gui.lua b/modules/gui.lua index ea3c0ebb9..8b0325ee7 100644 --- a/modules/gui.lua +++ b/modules/gui.lua @@ -1518,6 +1518,7 @@ pfUI:RegisterModule("gui", "vanilla:tbc", function () CreateConfig(U["mapreveal"], T["Map Reveal Color"], C.appearance.worldmap, "mapreveal_color", "color") CreateConfig(U["mapreveal"], T["Map Exploration Points"], C.appearance.worldmap, "mapexploration", "checkbox") CreateConfig(U["mapcolors"], T["Map Group/Raid Circle Size"], C.appearance.worldmap, "groupcircles", "dropdown", pfUI.gui.dropdowns.mapcircle) + CreateConfig(U["mapcolors"], T["Colorize player name on WorldMap and BattlefieldMinimap"], C.appearance.worldmap, "colornames", "checkbox") CreateConfig(U["map"], T["Map Tooltip Scale"], C.appearance.worldmap, "tooltipsize", "dropdown", pfUI.gui.dropdowns.maptooltip) CreateConfig(nil) -- spacer CreateConfig(nil, T["Enable Frame Shadow"], C.appearance.border, "shadow", "checkbox") diff --git a/modules/mapcolors.lua b/modules/mapcolors.lua index d012d5e62..e97610fe1 100644 --- a/modules/mapcolors.lua +++ b/modules/mapcolors.lua @@ -1,93 +1,107 @@ -- adds class colored circles on world and battlefield map pfUI:RegisterModule("mapcolors", function () - pfUI.mapcolors = CreateFrame("Frame", nil, UIParent) - pfUI.mapcolors:SetScript("OnUpdate", function() - -- throttle to to one item per .1 second - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .1 end - - local frame, icon - - -- initialize all button names - if not this.buttons then - this.buttons = {} - - for i = 1, 4 do - icon = string.format("WorldMapParty%d", i) - this.buttons[icon] = string.format("party%d", i) - end - - for i = 1, 4 do - icon = string.format("BattlefieldMinimapParty%d", i) - this.buttons[icon] = string.format("party%d", i) + local function Initialize(unit_button_name) + local texture_size = tonumber(C.appearance.worldmap.groupcircles) + for i=1, MAX_PARTY_MEMBERS do + local frame = _G[unit_button_name.."Party"..i] + frame.icon = _G[unit_button_name.."Party"..i.."Icon"] + frame.icon:SetTexture(pfUI.media["img:circleparty"]) + frame.icon:SetVertexColor(.5, 1, .5) + SetAllPointsOffset(frame.icon, frame, texture_size, -texture_size) + end + for i=1, MAX_RAID_MEMBERS do + local frame = _G[unit_button_name.."Raid"..i] + frame.icon = _G[unit_button_name.."Raid"..i.."Icon"] + frame.icon:SetTexture(pfUI.media["img:circleraid"]) + frame.icon:SetVertexColor(.5, 1, .5) + SetAllPointsOffset(frame.icon, frame, texture_size, -texture_size) + end + end + local function UpdateTexture(frame) + if UnitInParty(frame.unit) then + frame.icon:SetTexture(pfUI.media["img:circleparty"]) + else + frame.icon:SetTexture(pfUI.media["img:circleraid"]) + end + end + local function UpdateTextureColor(frame) + if UnitExists(frame.unit) then + local _, class = UnitClass(frame.unit) + local color = RAID_CLASS_COLORS[class] + frame.icon:SetVertexColor(color.r, color.g, color.b) + else + frame.icon:SetVertexColor(.5, 1, .5) + end + end + local function UpdateUnitFrames(unit_button_name) + if GetNumRaidMembers() > 0 then + for i=1, MAX_RAID_MEMBERS do + local frame = _G[unit_button_name.."Raid"..i] + UpdateTexture(frame) + UpdateTextureColor(frame) end - - for i = 1, 40 do - icon = string.format("BattlefieldMinimapRaid%d", i) - this.buttons[icon] = string.format("raid%d", i) + elseif GetNumPartyMembers() > 0 then + for i=1, MAX_PARTY_MEMBERS do + local frame = _G[unit_button_name.."Party"..i] + UpdateTextureColor(frame) end - - for i = 1, 40 do - icon = string.format("WorldMapRaid%d", i) - this.buttons[icon] = string.format("raid%d", i) + end + end + local function ColorizeName(frame) + local _, class = UnitClass(frame.unit) + local color = RAID_CLASS_COLORS[class] + frame.name = frame.name or UnitName(frame.unit) + frame.name = '|c'..color.colorStr..frame.name..'|r' + end + local function UpdateUnitColors(unit_button_name, tooltip) + local tooltipText = "" + if unit_button_name == 'WorldMap' then + -- Check player + if MouseIsOver(WorldMapPlayer) then + ColorizeName(WorldMapPlayer) + tooltipText = WorldMapPlayer.name end end - - -- update all available buttons - local ingroup - for name, unitstr in pairs(this.buttons) do - frame = _G[name] - - if frame and UnitExists(unitstr) then - icon = _G[name.."Icon"] - icon:SetTexture() - - -- create icon if not yet existing - if not frame.pfIcon then - frame.pfIcon = frame:CreateTexture(nil, "OVERLAY") - SetAllPointsOffset(frame.pfIcon, frame, this.size, -this.size) - end - - -- check if unit is in same group - ingroup = nil - for i=1,5 do -- check if unit is in group - if UnitName(string.format("party%d", i)) == UnitName(unitstr) then - ingroup = true - end - end - - -- update texture according to raid/group state - if ingroup and frame.pfIcon.ingroup ~= "PARTY" then - frame.pfIcon:SetTexture(pfUI.media["img:circleparty"]) - frame.pfIcon.ingroup = "PARTY" - elseif not ingroup and frame.pfIcon.ingroup ~= "RAID" then - frame.pfIcon:SetTexture(pfUI.media["img:circleraid"]) - frame.pfIcon.ingroup = "RAID" - end - - -- detect unit class and set color - local _, class = UnitClass(unitstr) - local color = RAID_CLASS_COLORS[class] - if color then - frame.pfIcon:SetVertexColor(color.r, color.g, color.b) - else - frame.pfIcon:SetVertexColor(.5,1,.5) - end + -- Check party + for i=1, MAX_PARTY_MEMBERS do + local frame = _G[unit_button_name.."Party"..i] + if frame:IsVisible() and MouseIsOver(frame) then + ColorizeName(frame) + tooltipText = tooltipText.."\n"..frame.name end end - end) - - pfUI.mapcolors.UpdateConfig = function() - pfUI.mapcolors.size = tonumber(C.appearance.worldmap.groupcircles) - - if not pfUI.mapcolors.buttons then return end - for name, unitstr in pairs(pfUI.mapcolors.buttons) do - frame = _G[name] - - if frame and frame.pfIcon then - SetAllPointsOffset(frame.pfIcon, frame, pfUI.mapcolors.size, -pfUI.mapcolors.size) + --Check Raid + for i=1, MAX_RAID_MEMBERS do + local frame = _G[unit_button_name.."Raid"..i] + if frame:IsVisible() and MouseIsOver(frame) then + ColorizeName(frame) + tooltipText = tooltipText.."\n"..frame.name end end + tooltip:SetText(tooltipText) + tooltip:Show() end - pfUI.mapcolors:UpdateConfig() + -- WorldMap + Initialize('WorldMap') + hooksecurefunc('WorldMapButton_OnUpdate', function() + UpdateUnitFrames('WorldMap') + end) + if C.appearance.worldmap.colornames == "1" then + hooksecurefunc('WorldMapUnit_OnEnter', function() + UpdateUnitColors('WorldMap', WorldMapTooltip) + end) + end + -- BattlefieldMinimap + HookAddonOrVariable("Blizzard_BattlefieldMinimap", function() + Initialize('BattlefieldMinimap') + hooksecurefunc('BattlefieldMinimap_OnUpdate', function() + UpdateUnitFrames('BattlefieldMinimap') + end) + if C.appearance.worldmap.colornames == "1" then + hooksecurefunc('BattlefieldMinimapUnit_OnEnter', function() + UpdateUnitColors('BattlefieldMinimap', GameTooltip) + end) + end + end) end) From 777b241c2ca4b8bc3c9dd5a6bbae2cc2b2f4a8eb Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Fri, 31 May 2024 23:11:51 +0200 Subject: [PATCH 02/70] perf (libpredict.lua): optimize the "CastSpellByName" post-hook - pfUI.uf.mouseover now gets cached the first time the hook is triggered and if the mouseover module is disabled we set the cache to the empty object {} as a safety net - we now detect attempts to get the player's name via UnitName("player") and we simply return the 'player' variable we already have to save ourselves a function call - also removed a duplicate call to UnitName("target") which was unnecessary --- libs/libpredict.lua | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/libs/libpredict.lua b/libs/libpredict.lua index e4d44c172..bec1f0682 100644 --- a/libs/libpredict.lua +++ b/libs/libpredict.lua @@ -316,18 +316,24 @@ hooksecurefunc("CastSpell", function(id, bookType) spell_queue[3] = UnitName("target") and UnitCanAssist("player", "target") and UnitName("target") or UnitName("player") end, true) +local _cached_pfui_uf_mouseover -- will get cached upon first use in one of the hooks below hooksecurefunc("CastSpellByName", function(effect, target) if not libpredict.sender.enabled then return end - local effect, rank = libspell.GetSpellInfo(effect) - if not effect then return end - local mouseover = pfUI and pfUI.uf and pfUI.uf.mouseover and pfUI.uf.mouseover.unit - mouseover = mouseover and UnitCanAssist("player", mouseover) and UnitName(mouseover) - - local default = UnitName("target") and UnitCanAssist("player", "target") and UnitName("target") or UnitName("player") - - spell_queue[1] = effect - spell_queue[2] = effect.. ( rank or "" ) - spell_queue[3] = mouseover or default + local effectRaw, rank = libspell.GetSpellInfo(effect) + if not effectRaw then return end + + _cached_pfui_uf_mouseover = _cached_pfui_uf_mouseover or pfUI.uf.mouseover or {} + local pfui_uf_mouseover_unit = _cached_pfui_uf_mouseover.unit + + spell_queue[1] = effectRaw + spell_queue[2] = effectRaw .. (rank or "") + spell_queue[3] = pfui_uf_mouseover_unit == "player" + and player + or ( + (pfui_uf_mouseover_unit and UnitCanAssist("player", pfui_uf_mouseover_unit)) + and UnitName(pfui_uf_mouseover_unit) -- mouseover unit name + or (UnitCanAssist("player", "target") and UnitName("target") or player) -- or default + ) end, true) local scanner = libtipscan:GetScanner("prediction") From 84d09a0a9a5bc21d224cea792ba4442ffc3378d3 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Fri, 31 May 2024 23:15:05 +0200 Subject: [PATCH 03/70] fix (libpredict.lua): align the implementations of "CastSpell" and "UseAction" with that of "CastSpellByName" in terms of getting the proper unit-name these two post-hook functions now take the mouse-over value (if any) into account just like we do in the "CastSpellByName" post-hook --- libs/libpredict.lua | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/libs/libpredict.lua b/libs/libpredict.lua index bec1f0682..bdd2a2545 100644 --- a/libs/libpredict.lua +++ b/libs/libpredict.lua @@ -307,16 +307,28 @@ local function UpdateCache(spell, heal, crit) end -- Gather Data by User Actions + +local _cached_pfui_uf_mouseover -- will get cached upon first use in one of the hooks below + hooksecurefunc("CastSpell", function(id, bookType) if not libpredict.sender.enabled then return end - local effect, rank = libspell.GetSpellInfo(id, bookType) - if not effect then return end - spell_queue[1] = effect - spell_queue[2] = effect.. ( rank or "" ) - spell_queue[3] = UnitName("target") and UnitCanAssist("player", "target") and UnitName("target") or UnitName("player") -end, true) + local effectRaw, rank = libspell.GetSpellInfo(id, bookType) + if not effectRaw then return end + + _cached_pfui_uf_mouseover = _cached_pfui_uf_mouseover or pfUI.uf.mouseover or {} + local pfui_uf_mouseover_unit = _cached_pfui_uf_mouseover.unit -local _cached_pfui_uf_mouseover -- will get cached upon first use in one of the hooks below + spell_queue[1] = effectRaw + spell_queue[2] = effectRaw .. (rank or "") + spell_queue[3] = pfui_uf_mouseover_unit == "player" + and player + or ( + (pfui_uf_mouseover_unit and UnitCanAssist("player", pfui_uf_mouseover_unit)) + and UnitName(pfui_uf_mouseover_unit) -- mouseover unit name + or (UnitCanAssist("player", "target") and UnitName("target") or player) -- or default + ) +end, true) + hooksecurefunc("CastSpellByName", function(effect, target) if not libpredict.sender.enabled then return end local effectRaw, rank = libspell.GetSpellInfo(effect) @@ -340,12 +352,23 @@ local scanner = libtipscan:GetScanner("prediction") hooksecurefunc("UseAction", function(slot, target, selfcast) if not libpredict.sender.enabled then return end if GetActionText(slot) or not IsCurrentAction(slot) then return end + scanner:SetAction(slot) local effect, rank = scanner:Line(1) if not effect then return end + + _cached_pfui_uf_mouseover = _cached_pfui_uf_mouseover or pfUI.uf.mouseover or {} + local pfui_uf_mouseover_unit = _cached_pfui_uf_mouseover.unit + spell_queue[1] = effect - spell_queue[2] = effect.. ( rank or "" ) - spell_queue[3] = selfcast and UnitName("player") or UnitName("target") and UnitCanAssist("player", "target") and UnitName("target") or UnitName("player") + spell_queue[2] = effect .. (rank or "") + spell_queue[3] = (selfcast or pfui_uf_mouseover_unit == "player") + and player + or ( + (pfui_uf_mouseover_unit and UnitCanAssist("player", pfui_uf_mouseover_unit)) + and UnitName(pfui_uf_mouseover_unit) -- mouseover unit name + or (UnitCanAssist("player", "target") and UnitName("target") or player) -- or default + ) end, true) libpredict.sender = CreateFrame("Frame", "pfPredictionSender", UIParent) From 4ba506516778f18fb96df6a9976b703919859c27 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 01:46:17 +0200 Subject: [PATCH 04/70] fix (libspell.lua): GetSpellInfo() now properly spots the spell-cast-time and range components in the spell tooltip to fix this bug we had to pass 'false' as the 2nd argument to scanner:Find() to disable "exact matching" in it --- libs/libspell.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/libspell.lua b/libs/libspell.lua index 5e19e1f63..1ee2008e5 100644 --- a/libs/libspell.lua +++ b/libs/libspell.lua @@ -115,9 +115,10 @@ function libspell.GetSpellInfo(index, bookType) if id then scanner:SetSpell(id, bookType) - local _, sec = scanner:Find(gsub(SPELL_CAST_TIME_SEC, "%%.3g", "%(.+%)")) - local _, min = scanner:Find(gsub(SPELL_CAST_TIME_MIN, "%%.3g", "%(.+%)")) - local _, range = scanner:Find(gsub(SPELL_RANGE, "%%s", "%(.+%)")) + local _, sec = scanner:Find(gsub(SPELL_CAST_TIME_SEC, "%%.3g", "%(.+%)"), false) + local _, min = scanner:Find(gsub(SPELL_CAST_TIME_MIN, "%%.3g", "%(.+%)"), false) + local _, range = scanner:Find(gsub(SPELL_RANGE, "%%s", "%(.+%)"), false) + castingTime = (tonumber(sec) or tonumber(min) or 0) * 1000 if range then local _, _, min, max = string.find(range, "(.+)-(.+)") From 6845a998520b5271cd9f92362359c0c21b907dba Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 02:04:50 +0200 Subject: [PATCH 05/70] feat (libspell): GetSpellInfo() now also returns the numeric-spell-id of the spell and its book-type --- libs/libspell.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/libspell.lua b/libs/libspell.lua index 5e19e1f63..c6f9a05de 100644 --- a/libs/libspell.lua +++ b/libs/libspell.lua @@ -83,10 +83,12 @@ end -- [number] Casting time of the spell in milliseconds -- [number] Minimum range from the target required to cast the spell -- [number] Maximum range from the target at which you can cast the spell +-- [number] The numeric spell-id of the spell +-- [number] The type of the spellbook that the spell is in local spellinfo = {} function libspell.GetSpellInfo(index, bookType) local cache = spellinfo[index] - if cache then return cache[1], cache[2], cache[3], cache[4], cache[5], cache[6] end + if cache then return cache[1], cache[2], cache[3], cache[4], cache[5], cache[6], cache[7], cache[8] end local name, rank, id local icon = "" @@ -131,8 +133,8 @@ function libspell.GetSpellInfo(index, bookType) end end - spellinfo[index] = { name, rank, icon, castingTime, minRange, maxRange } - return name, rank, icon, castingTime, minRange, maxRange + spellinfo[index] = { name, rank, icon, castingTime, minRange, maxRange, id, bookType } + return name, rank, icon, castingTime, minRange, maxRange, id, bookType end -- Reset all spell caches whenever new spells are learned/unlearned From 7cdba74abda0eda8d2caff750eabf12f40aaa11c Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 21:46:36 +0200 Subject: [PATCH 06/70] clean (buff.lua): remove GetNumBuffs() as it was unused --- modules/buff.lua | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/modules/buff.lua b/modules/buff.lua index f71144169..0cde0724f 100644 --- a/modules/buff.lua +++ b/modules/buff.lua @@ -211,19 +211,6 @@ pfUI:RegisterModule("buff", "vanilla:tbc", function () return buff end - local function GetNumBuffs() - local mh, mhtime, mhcharge, oh, ohtime, ohcharge = GetWeaponEnchantInfo() - local offset = (mh and 1 or 0) + (oh and 1 or 0) - - for i=1,32 do - local bid, untilCancelled = GetPlayerBuff(PLAYER_BUFF_START_ID+i, "HELPFUL") - if bid < 0 then - return i - 1 + offset - end - end - return 0 + offset - end - pfUI.buff = CreateFrame("Frame", "pfGlobalBuffFrame", UIParent) pfUI.buff:RegisterEvent("PLAYER_AURAS_CHANGED") pfUI.buff:RegisterEvent("UNIT_INVENTORY_CHANGED") From e7c7a009eaaa4455c50fa4bb27eac617ebc7983c Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 21:47:27 +0200 Subject: [PATCH 07/70] clean (api.lua): remove 'RangeCache' field as it was not being used anywhere --- api/api.lua | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/api/api.lua b/api/api.lua index b9f0420c0..da804f80f 100644 --- a/api/api.lua +++ b/api/api.lua @@ -59,15 +59,14 @@ end -- It takes care of the rangecheck module if existing. -- unit [string] A unit to query (string, unitID) -- return: [bool] "1" if in range otherwise "nil" -local RangeCache = {} function pfUI.api.UnitInRange(unit) - if not UnitExists(unit) or not UnitIsVisible(unit) then - return nil - elseif CheckInteractDistance(unit, 4) then - return 1 - else - return librange:UnitInSpellRange(unit) - end + if not UnitExists(unit) or not UnitIsVisible(unit) then + return nil + elseif CheckInteractDistance(unit, 4) then + return 1 + else + return librange:UnitInSpellRange(unit) + end end -- [ RunOOC ] From 8bdbd2b5bf9ddaf0dff757cfbf8cfe12b47bd46a Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 21:52:42 +0200 Subject: [PATCH 08/70] feat (api.lua): introduce pfUI.api.GetPlayerBuffX() we intentionally differentiated the name as 'GetPlayerBuffX' (note the 'X' at the end) so as to ensure that we won't accidentally break 3rd party pfui-addons that import the pfUI environment expecting GetPlayerBuff() to work exactly like in vanilla in terms of its 1st parameter (which is not the case with GetPlayerBuffX()) --- api/api.lua | 1859 +++++++++++++++++++++++++++------------------------ 1 file changed, 996 insertions(+), 863 deletions(-) diff --git a/api/api.lua b/api/api.lua index da804f80f..2ab0c5839 100644 --- a/api/api.lua +++ b/api/api.lua @@ -14,11 +14,15 @@ mod = math.mod or mod -- 'subject' [string] String to split. -- return: [list] a list of strings. function pfUI.api.strsplit(delimiter, subject) - if not subject then return nil end - local delimiter, fields = delimiter or ":", {} - local pattern = string.format("([^%s]+)", delimiter) - string.gsub(subject, pattern, function(c) fields[table.getn(fields)+1] = c end) - return unpack(fields) + if not subject then + return nil + end + local delimiter, fields = delimiter or ":", {} + local pattern = string.format("([^%s]+)", delimiter) + string.gsub(subject, pattern, function(c) + fields[table.getn(fields) + 1] = c + end) + return unpack(fields) end -- [ isempty ] @@ -26,11 +30,13 @@ end -- 'tbl' [table] the table that shall be checked -- return: [boolean] result of the check. function pfUI.api.isempty(tbl) - if not tbl then return true end - for k, v in pairs(tbl) do - return false - end - return true + if not tbl then + return true + end + for k, v in pairs(tbl) do + return false + end + return true end -- [ checkversion ] @@ -43,15 +49,15 @@ end -- to the given value, otherwise returns nil. local major, minor, fix = nil, nil, nil function pfUI.api.checkversion(chkmajor, chkminor, chkfix) - if not major and not minor and not fix then - -- load and convert current version - major, minor, fix = pfUI.api.strsplit(".", tostring(pfUI_config.version)) - major, minor, fix = tonumber(major) or 0, tonumber(minor) or 0, tonumber(fix) or 0 - end - - local chkversion = chkmajor + chkminor/100 + chkfix/10000 - local curversion = major + minor/100 + fix/10000 - return curversion <= chkversion and true or nil + if not major and not minor and not fix then + -- load and convert current version + major, minor, fix = pfUI.api.strsplit(".", tostring(pfUI_config.version)) + major, minor, fix = tonumber(major) or 0, tonumber(minor) or 0, tonumber(fix) or 0 + end + + local chkversion = chkmajor + chkminor / 100 + chkfix / 10000 + local curversion = major + minor / 100 + fix / 10000 + return curversion <= chkversion and true or nil end -- [ UnitInRange ] @@ -76,18 +82,23 @@ end -- nil if the function already exists in queue local queue, frame = {} function pfUI.api.RunOOC(func) - if not frame then - frame = CreateFrame("Frame") - frame:SetScript("OnUpdate", function() - if InCombatLockdown and InCombatLockdown() then return end - for key, func in pairs(queue) do func(); queue[key] = nil end - end) - end + if not frame then + frame = CreateFrame("Frame") + frame:SetScript("OnUpdate", function() + if InCombatLockdown and InCombatLockdown() then + return + end + for key, func in pairs(queue) do + func(); + queue[key] = nil + end + end) + end - if not queue[tostring(func)] then - queue[tostring(func)] = func - return true - end + if not queue[tostring(func)] then + queue[tostring(func)] = func + return true + end end -- [ UnitHasBuff ] @@ -96,15 +107,15 @@ end -- buff [string] The texture of the buff. -- return: [bool] true if unit has buff otherwise "nil" function pfUI.api.UnitHasBuff(unit, buff) - local hasbuff = nil - for i=1,32 do - if UnitBuff(unit, i) == buff then - hasbuff = true - break + local hasbuff = nil + for i = 1, 32 do + if UnitBuff(unit, i) == buff then + hasbuff = true + break + end end - end - return hasbuff + return hasbuff end -- [[ GetUnitColor ]] @@ -112,14 +123,14 @@ end -- unit [string] the unitstring -- return: [table] string, r, g, b function pfUI.api.GetUnitColor(unitstr) - local _, class = UnitClass(unitstr) + local _, class = UnitClass(unitstr) - local r, g, b = .8, .8, .8 - if RAID_CLASS_COLORS[class] then - r, g, b = RAID_CLASS_COLORS[class].r, RAID_CLASS_COLORS[class].g, RAID_CLASS_COLORS[class].b - end + local r, g, b = .8, .8, .8 + if RAID_CLASS_COLORS[class] then + r, g, b = RAID_CLASS_COLORS[class].r, RAID_CLASS_COLORS[class].g, RAID_CLASS_COLORS[class].b + end - return pfUI.api.rgbhex(r,g,b), r, g, b + return pfUI.api.rgbhex(r, g, b), r, g, b end -- [ strvertical ] @@ -127,12 +138,12 @@ end -- 'str' [string] String to columnize. -- return: [string] the string tranformed to a column. function pfUI.api.strvertical(str) - local _, len = string.gsub(str,"[^\128-\193]", "") - if (len == string.len(str)) then - return string.gsub(str, "(.)", "%1\n") - else - return string.gsub(str,"([%z\1-\127\194-\244][\128-\191]*)", "%1\n") - end + local _, len = string.gsub(str, "[^\128-\193]", "") + if (len == string.len(str)) then + return string.gsub(str, "(.)", "%1\n") + else + return string.gsub(str, "([%z\1-\127\194-\244][\128-\191]*)", "%1\n") + end end -- [ round ] @@ -141,12 +152,16 @@ end -- 'places' [int] amount of places after the comma. -- returns: [float] rounded number. function pfUI.api.round(input, places) - if not places then places = 0 end - if type(input) == "number" and type(places) == "number" then - local pow = 1 - for i = 1, places do pow = pow * 10 end - return floor(input * pow + 0.5) / pow - end + if not places then + places = 0 + end + if type(input) == "number" and type(places) == "number" then + local pow = 1 + for i = 1, places do + pow = pow * 10 + end + return floor(input * pow + 0.5) / pow + end end -- [ clamp ] @@ -156,11 +171,11 @@ end -- 'max' [number] maximum value. -- returns: [number] clamped value: 'x', 'min' or 'max' value itself. function pfUI.api.clamp(x, min, max) - if type(x) == "number" and type(min) == "number" and type(max) == "number" then - return x < min and min or x > max and max or x - else - return x - end + if type(x) == "number" and type(min) == "number" and type(max) == "number" then + return x < min and min or x > max and max or x + else + return x + end end -- [ modf ] @@ -168,11 +183,13 @@ end -- 'f' [float] the number to breakdown. -- returns: [int],[float] whole and fractional part. function pfUI.api.modf(f) - if modf then return modf(f) end - if f > 0 then - return math.floor(f), mod(f,1) - end - return math.ceil(f), mod(f,1) + if modf then + return modf(f) + end + if f > 0 then + return math.floor(f), mod(f, 1) + end + return math.ceil(f), mod(f, 1) end -- [ GetSlashCommands ] @@ -180,15 +197,15 @@ end -- 'text' [string] optional, a specific command to find -- return: [list] a list of all matching slash commands function pfUI.api.GetSlashCommands(text) - local cmds - for k, v in pairs(_G) do - if strfind(k, "^SLASH_") and (not text or v == text) then - cmds = cmds or {} - cmds[k] = v + local cmds + for k, v in pairs(_G) do + if strfind(k, "^SLASH_") and (not text or v == text) then + cmds = cmds or {} + cmds[k] = v + end end - end - return cmds + return cmds end -- [ RegisterSlashCommand ] @@ -199,16 +216,16 @@ end -- 'force' [boolean] force assign the command even if aleady provided -- by another function/addon. function pfUI.api.RegisterSlashCommand(name, cmds, func, force) - local counter = 1 + local counter = 1 - for _, cmd in pairs(cmds) do - if force or not pfUI.api.GetSlashCommands(cmd) then - _G["SLASH_"..name..counter] = cmd - counter = counter + 1 + for _, cmd in pairs(cmds) do + if force or not pfUI.api.GetSlashCommands(cmd) then + _G["SLASH_" .. name .. counter] = cmd + counter = counter + 1 + end end - end - _G.SlashCmdList[name] = func + _G.SlashCmdList[name] = func end -- [ GetCaptures ] @@ -217,15 +234,17 @@ end -- returns: [numbers] capture indexes local capture_cache = {} function pfUI.api.GetCaptures(pat) - local r = capture_cache - if not r[pat] then - for a, b, c, d, e in gfind(gsub(pat, "%((.+)%)", "%1"), gsub(pat, "%d%$", "%%(.-)$")) do - r[pat] = { a, b, c, d, e} + local r = capture_cache + if not r[pat] then + for a, b, c, d, e in gfind(gsub(pat, "%((.+)%)", "%1"), gsub(pat, "%d%$", "%%(.-)$")) do + r[pat] = { a, b, c, d, e } + end end - end - if not r[pat] then return nil, nil, nil, nil end - return r[pat][1], r[pat][2], r[pat][3], r[pat][4], r[pat][5] + if not r[pat] then + return nil, nil, nil, nil + end + return r[pat][1], r[pat][2], r[pat][3], r[pat][4], r[pat][5] end -- [ SanitizePattern ] @@ -234,23 +253,23 @@ end -- returns: [string] simplified gfind compatible pattern local sanitize_cache = {} function pfUI.api.SanitizePattern(pattern) - if not sanitize_cache[pattern] then - local ret = pattern - -- escape magic characters - ret = gsub(ret, "([%+%-%*%(%)%?%[%]%^])", "%%%1") - -- remove capture indexes - ret = gsub(ret, "%d%$","") - -- catch all characters - ret = gsub(ret, "(%%%a)","%(%1+%)") - -- convert all %s to .+ - ret = gsub(ret, "%%s%+",".+") - -- set priority to numbers over strings - ret = gsub(ret, "%(.%+%)%(%%d%+%)","%(.-%)%(%%d%+%)") - -- cache it - sanitize_cache[pattern] = ret - end - - return sanitize_cache[pattern] + if not sanitize_cache[pattern] then + local ret = pattern + -- escape magic characters + ret = gsub(ret, "([%+%-%*%(%)%?%[%]%^])", "%%%1") + -- remove capture indexes + ret = gsub(ret, "%d%$", "") + -- catch all characters + ret = gsub(ret, "(%%%a)", "%(%1+%)") + -- convert all %s to .+ + ret = gsub(ret, "%%s%+", ".+") + -- set priority to numbers over strings + ret = gsub(ret, "%(.%+%)%(%%d%+%)", "%(.-%)%(%%d%+%)") + -- cache it + sanitize_cache[pattern] = ret + end + + return sanitize_cache[pattern] end -- [ cmatch ] @@ -262,18 +281,18 @@ local a, b, c, d, e local _, va, vb, vc, vd, ve local ra, rb, rc, rd, re function pfUI.api.cmatch(str, pat) - -- read capture indexes - a, b, c, d, e = GetCaptures(pat) - _, _, va, vb, vc, vd, ve = string.find(str, pfUI.api.SanitizePattern(pat)) - - -- put entries into the proper return values - ra = e == 1 and ve or d == 1 and vd or c == 1 and vc or b == 1 and vb or va - rb = e == 2 and ve or d == 2 and vd or c == 2 and vc or a == 2 and va or vb - rc = e == 3 and ve or d == 3 and vd or a == 3 and va or b == 3 and vb or vc - rd = e == 4 and ve or a == 4 and va or c == 4 and vc or b == 4 and vb or vd - re = a == 5 and va or d == 5 and vd or c == 5 and vc or b == 5 and vb or ve - - return ra, rb, rc, rd, re + -- read capture indexes + a, b, c, d, e = GetCaptures(pat) + _, _, va, vb, vc, vd, ve = string.find(str, pfUI.api.SanitizePattern(pat)) + + -- put entries into the proper return values + ra = e == 1 and ve or d == 1 and vd or c == 1 and vc or b == 1 and vb or va + rb = e == 2 and ve or d == 2 and vd or c == 2 and vc or a == 2 and va or vb + rc = e == 3 and ve or d == 3 and vd or a == 3 and va or b == 3 and vb or vc + rd = e == 4 and ve or a == 4 and va or c == 4 and vc or b == 4 and vb or vd + re = a == 5 and va or d == 5 and vd or c == 5 and vc or b == 5 and vb or ve + + return ra, rb, rc, rd, re end -- [ GetItemLinkByName ] @@ -281,13 +300,13 @@ end -- 'name' [string] name of the item -- returns: [string] entire itemLink for the given item function pfUI.api.GetItemLinkByName(name) - for itemID = 1, 25818 do - local itemName, hyperLink, itemQuality = GetItemInfo(itemID) - if (itemName and itemName == name) then - local _, _, _, hex = GetItemQualityColor(tonumber(itemQuality)) - return hex.. "|H"..hyperLink.."|h["..itemName.."]|h|r" + for itemID = 1, 25818 do + local itemName, hyperLink, itemQuality = GetItemInfo(itemID) + if (itemName and itemName == name) then + local _, _, _, hex = GetItemQualityColor(tonumber(itemQuality)) + return hex .. "|H" .. hyperLink .. "|h[" .. itemName .. "]|h|r" + end end - end end -- [ GetItemCount ] @@ -295,24 +314,24 @@ end -- 'itemName' [string] name of the item -- returns: [int] the number of the given item function pfUI.api.GetItemCount(itemName) - local count = 0 - for bag = 4, 0, -1 do - for slot = 1, GetContainerNumSlots(bag) do - local _, itemCount = GetContainerItemInfo(bag, slot) - if itemCount then - local itemLink = GetContainerItemLink(bag,slot) - local _, _, itemParse = strfind(itemLink, "(%d+):") - local queryName = GetItemInfo(itemParse) - if queryName and queryName ~= "" then - if queryName == itemName then - count = count + itemCount - end + local count = 0 + for bag = 4, 0, -1 do + for slot = 1, GetContainerNumSlots(bag) do + local _, itemCount = GetContainerItemInfo(bag, slot) + if itemCount then + local itemLink = GetContainerItemLink(bag, slot) + local _, _, itemParse = strfind(itemLink, "(%d+):") + local queryName = GetItemInfo(itemParse) + if queryName and queryName ~= "" then + if queryName == itemName then + count = count + itemCount + end + end + end end - end end - end - return count + return count end -- [ FindItem ] @@ -321,20 +340,20 @@ end -- returns: [int] bag -- [int] slot function pfUI.api.FindItem(item) - for bag = 4, 0, -1 do - for slot = 1, GetContainerNumSlots(bag) do - local itemLink = GetContainerItemLink(bag,slot) - if itemLink then - local _, _, parse = strfind(itemLink, "(%d+):") - local query = GetItemInfo(parse) - if query and query ~= "" and string.lower(query) == string.lower(item) then - return bag, slot + for bag = 4, 0, -1 do + for slot = 1, GetContainerNumSlots(bag) do + local itemLink = GetContainerItemLink(bag, slot) + if itemLink then + local _, _, parse = strfind(itemLink, "(%d+):") + local query = GetItemInfo(parse) + if query and query ~= "" and string.lower(query) == string.lower(item) then + return bag, slot + end + end end - end end - end - return nil + return nil end -- [ GetBagFamily ] @@ -343,22 +362,36 @@ end -- 'bag' [int] the bag id -- returns: [string] the type of the bag, e.g "QUIVER" function pfUI.api.GetBagFamily(bag) - if bag == -2 then return "KEYRING" end - if bag == 0 then return "BAG" end -- backpack - if bag == -1 then return "BAG" end -- bank - - local _, _, id = strfind(GetInventoryItemLink("player", ContainerIDToInventoryID(bag)) or "", "item:(%d+)") - if id then - local _, _, _, _, _, itemType, subType = GetItemInfo(id) - local bagsubtype = L["bagtypes"][subType] - - if bagsubtype == "DEFAULT" then return "BAG" end - if bagsubtype == "SOULBAG" then return "SOULBAG" end - if bagsubtype == "QUIVER" then return "QUIVER" end - if bagsubtype == nil then return "SPECIAL" end - end - - return nil + if bag == -2 then + return "KEYRING" + end + if bag == 0 then + return "BAG" + end -- backpack + if bag == -1 then + return "BAG" + end -- bank + + local _, _, id = strfind(GetInventoryItemLink("player", ContainerIDToInventoryID(bag)) or "", "item:(%d+)") + if id then + local _, _, _, _, _, itemType, subType = GetItemInfo(id) + local bagsubtype = L["bagtypes"][subType] + + if bagsubtype == "DEFAULT" then + return "BAG" + end + if bagsubtype == "SOULBAG" then + return "SOULBAG" + end + if bagsubtype == "QUIVER" then + return "QUIVER" + end + if bagsubtype == nil then + return "SPECIAL" + end + end + + return nil end -- [ Abbreviate ] @@ -366,35 +399,35 @@ end -- 'number' [number] the number that should be abbreviated -- 'returns: [string] the abbreviated value function pfUI.api.Abbreviate(number) - if pfUI_config.unitframes.abbrevnum == "1" then - local sign = number < 0 and -1 or 1 - number = math.abs(number) - - if number > 1000000 then - return pfUI.api.round(number/1000000*sign,2) .. "m" - elseif number > 1000 then - return pfUI.api.round(number/1000*sign,2) .. "k" + if pfUI_config.unitframes.abbrevnum == "1" then + local sign = number < 0 and -1 or 1 + number = math.abs(number) + + if number > 1000000 then + return pfUI.api.round(number / 1000000 * sign, 2) .. "m" + elseif number > 1000 then + return pfUI.api.round(number / 1000 * sign, 2) .. "k" + end end - end - return number + return number end -- [ SendChatMessageWide ] -- Sends a message to widest audience the player can broadcast to -- 'msg' [string] the message to send function pfUI.api.SendChatMessageWide(msg) - local channel = "SAY" - if UnitInRaid("player") then - if ( IsRaidLeader() or IsRaidOfficer() ) then - channel = "RAID_WARNING" - else - channel = "RAID" + local channel = "SAY" + if UnitInRaid("player") then + if (IsRaidLeader() or IsRaidOfficer()) then + channel = "RAID_WARNING" + else + channel = "RAID" + end + elseif UnitExists("party1") then + channel = "PARTY" end - elseif UnitExists("party1") then - channel = "PARTY" - end - SendChatMessage(msg,channel) + SendChatMessage(msg, channel) end -- [ GroupInfoByName ] @@ -402,48 +435,47 @@ end -- 'name' [string] party or raid member -- 'group' [string] "raid" or "party" -- returns: [table] {name='name',unitId='unitId',Id=Id,lclass='lclass',class='class'} -do -- create a scope so we don't have to worry about upvalue collisions - local party, raid, unitinfo = {}, {}, {} - party[0] = "player" -- fake unit - for i=1, MAX_PARTY_MEMBERS do - party[i] = "party"..i - end - for i=1, MAX_RAID_MEMBERS do - raid[i] = "raid"..i - end - function pfUI.api.GroupInfoByName(name,group) - unitinfo = pfUI.api.wipe(unitinfo) - if group == "party" then - for i=0, MAX_PARTY_MEMBERS do - local unitName = UnitName(party[i]) - if unitName == name then - local lclass,class = UnitClass(party[i]) - if not (lclass and class) then - lclass,class = _G.UNKNOWN, "UNKNOWN" - end - unitinfo.name,unitinfo.unitId,unitinfo.Id,unitinfo.lclass,unitinfo.class = - unitName,party[i],i,lclass,class - return unitinfo - end - end - elseif group == "raid" then - for i=1, MAX_RAID_MEMBERS do - local unitName = UnitName(raid[i]) - if unitName == name then - local lclass,class = UnitClass(raid[i]) - if not (lclass and class) then - lclass,class = _G.UNKNOWN, "UNKNOWN" - end - unitinfo.name,unitinfo.unitId,unitinfo.Id,unitinfo.lclass,unitinfo.class = - unitName,raid[i],i,lclass,class - return unitinfo +do + -- create a scope so we don't have to worry about upvalue collisions + local party, raid, unitinfo = {}, {}, {} + party[0] = "player" -- fake unit + for i = 1, MAX_PARTY_MEMBERS do + party[i] = "party" .. i + end + for i = 1, MAX_RAID_MEMBERS do + raid[i] = "raid" .. i + end + function pfUI.api.GroupInfoByName(name, group) + unitinfo = pfUI.api.wipe(unitinfo) + if group == "party" then + for i = 0, MAX_PARTY_MEMBERS do + local unitName = UnitName(party[i]) + if unitName == name then + local lclass, class = UnitClass(party[i]) + if not (lclass and class) then + lclass, class = _G.UNKNOWN, "UNKNOWN" + end + unitinfo.name, unitinfo.unitId, unitinfo.Id, unitinfo.lclass, unitinfo.class = unitName, party[i], i, lclass, class + return unitinfo + end + end + elseif group == "raid" then + for i = 1, MAX_RAID_MEMBERS do + local unitName = UnitName(raid[i]) + if unitName == name then + local lclass, class = UnitClass(raid[i]) + if not (lclass and class) then + lclass, class = _G.UNKNOWN, "UNKNOWN" + end + unitinfo.name, unitinfo.unitId, unitinfo.Id, unitinfo.lclass, unitinfo.class = unitName, raid[i], i, lclass, class + return unitinfo + end + end end - end + -- fallback for GetMasterLootCandidate not updating immediately for leavers + unitinfo.lclass, unitinfo.class = _G.UNKNOWN, "UNKNOWN" + return unitinfo end - -- fallback for GetMasterLootCandidate not updating immediately for leavers - unitinfo.lclass,unitinfo.class = _G.UNKNOWN, "UNKNOWN" - return unitinfo - end end -- [ HookScript ] @@ -452,11 +484,13 @@ end -- 'script' [string] the handler to hook -- 'func' [function] the function that should be added function HookScript(f, script, func) - local prev = f:GetScript(script) - f:SetScript(script, function(a1,a2,a3,a4,a5,a6,a7,a8,a9) - if prev then prev(a1,a2,a3,a4,a5,a6,a7,a8,a9) end - func(a1,a2,a3,a4,a5,a6,a7,a8,a9) - end) + local prev = f:GetScript(script) + f:SetScript(script, function(a1, a2, a3, a4, a5, a6, a7, a8, a9) + if prev then + prev(a1, a2, a3, a4, a5, a6, a7, a8, a9) + end + func(a1, a2, a3, a4, a5, a6, a7, a8, a9) + end) end -- [ HookAddonOrVariable ] @@ -464,54 +498,54 @@ end -- 'addon' [string] addon or variable name -- 'func' [function] function that should run function pfUI.api.HookAddonOrVariable(addon, func) - local lurker = CreateFrame("Frame", nil) - lurker.func = func - lurker:RegisterEvent("ADDON_LOADED") - lurker:RegisterEvent("VARIABLES_LOADED") - lurker:RegisterEvent("PLAYER_ENTERING_WORLD") - lurker:SetScript("OnEvent",function() - -- only run when config is available - if event == "ADDON_LOADED" and not this.foundConfig then - return - elseif event == "VARIABLES_LOADED" then - this.foundConfig = true - end - - if IsAddOnLoaded(addon) or _G[addon] then - this:func() - this:UnregisterAllEvents() - end - end) + local lurker = CreateFrame("Frame", nil) + lurker.func = func + lurker:RegisterEvent("ADDON_LOADED") + lurker:RegisterEvent("VARIABLES_LOADED") + lurker:RegisterEvent("PLAYER_ENTERING_WORLD") + lurker:SetScript("OnEvent", function() + -- only run when config is available + if event == "ADDON_LOADED" and not this.foundConfig then + return + elseif event == "VARIABLES_LOADED" then + this.foundConfig = true + end + + if IsAddOnLoaded(addon) or _G[addon] then + this:func() + this:UnregisterAllEvents() + end + end) end -- [ QueueFunction ] -- Add functions to a FIFO queue for execution after a short delay. -- '...' [vararg] function, [arguments] local timer -function pfUI.api.QueueFunction(a1,a2,a3,a4,a5,a6,a7,a8,a9) - if not timer then - timer = CreateFrame("Frame") - timer.queue = {} - timer.interval = TOOLTIP_UPDATE_TIME - timer.DeQueue = function() - local item = table.remove(timer.queue,1) - if item then - item[1](item[2],item[3],item[4],item[5],item[6],item[7],item[8],item[9]) - end - if table.getn(timer.queue) == 0 then - timer:Hide() -- no need to run the OnUpdate when the queue is empty - end - end - timer:SetScript("OnUpdate",function() - this.sinceLast = (this.sinceLast or 0) + arg1 - while (this.sinceLast > this.interval) do - this.DeQueue() - this.sinceLast = this.sinceLast - this.interval - end - end) - end - table.insert(timer.queue,{a1,a2,a3,a4,a5,a6,a7,a8,a9}) - timer:Show() -- start the OnUpdate +function pfUI.api.QueueFunction(a1, a2, a3, a4, a5, a6, a7, a8, a9) + if not timer then + timer = CreateFrame("Frame") + timer.queue = {} + timer.interval = TOOLTIP_UPDATE_TIME + timer.DeQueue = function() + local item = table.remove(timer.queue, 1) + if item then + item[1](item[2], item[3], item[4], item[5], item[6], item[7], item[8], item[9]) + end + if table.getn(timer.queue) == 0 then + timer:Hide() -- no need to run the OnUpdate when the queue is empty + end + end + timer:SetScript("OnUpdate", function() + this.sinceLast = (this.sinceLast or 0) + arg1 + while (this.sinceLast > this.interval) do + this.DeQueue() + this.sinceLast = this.sinceLast - this.interval + end + end) + end + table.insert(timer.queue, { a1, a2, a3, a4, a5, a6, a7, a8, a9 }) + timer:Show() -- start the OnUpdate end -- [ Create Gold String ] @@ -520,18 +554,24 @@ end -- return: [string] a colorized string which is split into -- gold,silver and copper values. function pfUI.api.CreateGoldString(money) - if type(money) ~= "number" then return "-" end + if type(money) ~= "number" then + return "-" + end - local gold = floor(money/ 100 / 100) - local silver = floor(mod((money/100),100)) - local copper = floor(mod(money,100)) + local gold = floor(money / 100 / 100) + local silver = floor(mod((money / 100), 100)) + local copper = floor(mod(money, 100)) - local string = "" - if gold > 0 then string = string .. "|cffffffff" .. gold .. "|cffffd700g" end - if silver > 0 or gold > 0 then string = string .. "|cffffffff " .. silver .. "|cffc7c7cfs" end - string = string .. "|cffffffff " .. copper .. "|cffeda55fc" + local string = "" + if gold > 0 then + string = string .. "|cffffffff" .. gold .. "|cffffd700g" + end + if silver > 0 or gold > 0 then + string = string .. "|cffffffff " .. silver .. "|cffc7c7cfs" + end + string = string .. "|cffffffff " .. copper .. "|cffeda55fc" - return string + return string end -- [ Enable Movable ] @@ -539,46 +579,52 @@ end -- 'name' [frame/string] Name of the Frame that should be movable -- 'addon' [string] Addon that must be loaded before being able to access the frame -- 'blacklist' [table] A list of frames that should be deactivated for mouse usage -local function OnDragStart() this:StartMoving() end -local function OnDragStop() this:StopMovingOrSizing() end +local function OnDragStart() + this:StartMoving() +end +local function OnDragStop() + this:StopMovingOrSizing() +end function pfUI.api.EnableMovable(name, addon, blacklist) - if addon then - local scan = CreateFrame("Frame") - scan:RegisterEvent("ADDON_LOADED") - scan:SetScript("OnEvent", function() - if arg1 == addon then - local frame = _G[name] - + if addon then + local scan = CreateFrame("Frame") + scan:RegisterEvent("ADDON_LOADED") + scan:SetScript("OnEvent", function() + if arg1 == addon then + local frame = _G[name] + + if blacklist then + for _, disable in pairs(blacklist) do + _G[disable]:EnableMouse(false) + end + end + + frame:SetMovable(true) + frame:EnableMouse(true) + frame:RegisterForDrag("LeftButton") + frame:SetScript("OnDragStart", OnDragStart) + frame:SetScript("OnDragStop", OnDragStop) + + this:UnregisterAllEvents() + end + end) + else if blacklist then - for _, disable in pairs(blacklist) do - _G[disable]:EnableMouse(false) - end + for _, disable in pairs(blacklist) do + _G[disable]:EnableMouse(false) + end end + local frame = name + if type(name) == "string" then + frame = _G[name] + end frame:SetMovable(true) frame:EnableMouse(true) frame:RegisterForDrag("LeftButton") frame:SetScript("OnDragStart", OnDragStart) frame:SetScript("OnDragStop", OnDragStop) - - this:UnregisterAllEvents() - end - end) - else - if blacklist then - for _, disable in pairs(blacklist) do - _G[disable]:EnableMouse(false) - end - end - - local frame = name - if type(name) == "string" then frame = _G[name] end - frame:SetMovable(true) - frame:EnableMouse(true) - frame:RegisterForDrag("LeftButton") - frame:SetScript("OnDragStart", OnDragStart) - frame:SetScript("OnDragStop", OnDragStop) - end + end end -- [ Copy Table ] @@ -587,21 +633,21 @@ end -- 'src' [table] the table that should be copied. -- return: [table] the replicated table. function pfUI.api.CopyTable(src) - local lookup_table = {} - local function _copy(src) - if type(src) ~= "table" then - return src - elseif lookup_table[src] then - return lookup_table[src] - end - local new_table = {} - lookup_table[src] = new_table - for index, value in pairs(src) do - new_table[_copy(index)] = _copy(value) - end - return setmetatable(new_table, getmetatable(src)) - end - return _copy(src) + local lookup_table = {} + local function _copy(src) + if type(src) ~= "table" then + return src + elseif lookup_table[src] then + return lookup_table[src] + end + local new_table = {} + lookup_table[src] = new_table + for index, value in pairs(src) do + new_table[_copy(index)] = _copy(value) + end + return setmetatable(new_table, getmetatable(src)) + end + return _copy(src) end -- [ Wipe Table ] @@ -609,20 +655,20 @@ end -- 'src' [table] the table that should be emptied. -- return: [table] the emptied table. function pfUI.api.wipe(src) - -- notes: table.insert, table.remove will have undefined behavior - -- when used on tables emptied this way because Lua removes nil - -- entries from tables after an indeterminate time. - -- Instead of table.insert(t,v) use t[table.getn(t)+1]=v as table.getn collapses nil entries. - -- There are no issues with hash tables, t[k]=v where k is not a number behaves as expected. - local mt = getmetatable(src) or {} - if mt.__mode == nil or mt.__mode ~= "kv" then - mt.__mode = "kv" - src=setmetatable(src,mt) - end - for k in pairs(src) do - src[k] = nil - end - return src + -- notes: table.insert, table.remove will have undefined behavior + -- when used on tables emptied this way because Lua removes nil + -- entries from tables after an indeterminate time. + -- Instead of table.insert(t,v) use t[table.getn(t)+1]=v as table.getn collapses nil entries. + -- There are no issues with hash tables, t[k]=v where k is not a number behaves as expected. + local mt = getmetatable(src) or {} + if mt.__mode == nil or mt.__mode ~= "kv" then + mt.__mode = "kv" + src = setmetatable(src, mt) + end + for k in pairs(src) do + src[k] = nil + end + return src end -- [ Load Movable ] @@ -630,52 +676,54 @@ end -- 'frame' [frame] the frame that should be positioned. -- 'init' [bool] treats the current position as initial data function pfUI.api.LoadMovable(frame, init) - -- update position data - if not frame.posdata or init then - frame.posdata = { scale = frame:GetScale(), pos = {} } - for i=1,frame:GetNumPoints() do - frame.posdata.pos[i] = { frame:GetPoint(i) } - end - end - - if pfUI_config["position"][frame:GetName()] then - if pfUI_config["position"][frame:GetName()]["parent"] then - frame:SetParent(_G[pfUI_config["position"][frame:GetName()]["parent"]]) + -- update position data + if not frame.posdata or init then + frame.posdata = { scale = frame:GetScale(), pos = {} } + for i = 1, frame:GetNumPoints() do + frame.posdata.pos[i] = { frame:GetPoint(i) } + end end - if pfUI_config["position"][frame:GetName()]["scale"] then - frame:SetScale(pfUI_config["position"][frame:GetName()].scale) - end + if pfUI_config["position"][frame:GetName()] then + if pfUI_config["position"][frame:GetName()]["parent"] then + frame:SetParent(_G[pfUI_config["position"][frame:GetName()]["parent"]]) + end - if pfUI_config["position"][frame:GetName()]["xpos"] then - local anchor = pfUI_config["position"][frame:GetName()]["anchor"] or "TOPLEFT" - frame:ClearAllPoints() - frame:SetPoint(anchor, pfUI_config["position"][frame:GetName()].xpos, pfUI_config["position"][frame:GetName()].ypos) - end - elseif frame.posdata and frame.posdata.pos[1] then - frame:ClearAllPoints() - frame:SetScale(frame.posdata.scale) + if pfUI_config["position"][frame:GetName()]["scale"] then + frame:SetScale(pfUI_config["position"][frame:GetName()].scale) + end - for id, point in pairs(frame.posdata.pos) do - local a, b, c, d, e = unpack(point) - if a and b then frame:SetPoint(a,b,c,d,e) end + if pfUI_config["position"][frame:GetName()]["xpos"] then + local anchor = pfUI_config["position"][frame:GetName()]["anchor"] or "TOPLEFT" + frame:ClearAllPoints() + frame:SetPoint(anchor, pfUI_config["position"][frame:GetName()].xpos, pfUI_config["position"][frame:GetName()].ypos) + end + elseif frame.posdata and frame.posdata.pos[1] then + frame:ClearAllPoints() + frame:SetScale(frame.posdata.scale) + + for id, point in pairs(frame.posdata.pos) do + local a, b, c, d, e = unpack(point) + if a and b then + frame:SetPoint(a, b, c, d, e) + end + end end - end end -- [ Save Movable ] -- Save the positions of a Frame. -- 'frame' [frame] the frame that should be saved. function pfUI.api.SaveMovable(frame, scale) - local anchor, _, _, xpos, ypos = frame:GetPoint() - C.position[frame:GetName()] = C.position[frame:GetName()] or {} - C.position[frame:GetName()]["xpos"] = round(xpos) - C.position[frame:GetName()]["ypos"] = round(ypos) - C.position[frame:GetName()]["anchor"] = anchor - C.position[frame:GetName()]["parent"] = frame:GetParent() and frame:GetParent():GetName() or nil - if scale then - C.position[frame:GetName()]["scale"] = frame:GetScale() - end + local anchor, _, _, xpos, ypos = frame:GetPoint() + C.position[frame:GetName()] = C.position[frame:GetName()] or {} + C.position[frame:GetName()]["xpos"] = round(xpos) + C.position[frame:GetName()]["ypos"] = round(ypos) + C.position[frame:GetName()]["anchor"] = anchor + C.position[frame:GetName()]["parent"] = frame:GetParent() and frame:GetParent():GetName() or nil + if scale then + C.position[frame:GetName()]["scale"] = frame:GetScale() + end end -- [ Update Movable ] @@ -684,25 +732,25 @@ end -- 'frame' [frame] the frame that should be updated. -- 'init' [bool] treats the current position as initial data function pfUI.api.UpdateMovable(frame, init) - local name = frame:GetName() + local name = frame:GetName() - if pfUI_config.global.offscreen == "0" then - frame:SetClampedToScreen(true) - end + if pfUI_config.global.offscreen == "0" then + frame:SetClampedToScreen(true) + end - if not pfUI.movables[name] then - pfUI.movables[name] = frame - end + if not pfUI.movables[name] then + pfUI.movables[name] = frame + end - LoadMovable(frame, init) + LoadMovable(frame, init) end -- [ Remove Movable ] -- Removes a Frame from the movable list. -- 'frame' [frame] the frame that should be removed. function pfUI.api.RemoveMovable(frame) - local name = frame:GetName() - pfUI.movables[name] = nil + local name = frame:GetName() + pfUI.movables[name] = nil end -- [ AlignToPosition ] @@ -712,23 +760,23 @@ end -- 'position' [string] where it should appear, takes the following: -- "TOP", "RIGHT", "BOTTOM", "LEFT" function pfUI.api.AlignToPosition(frame, anchor, position, spacing) - frame:ClearAllPoints() - if position == "TOP" and anchor then - frame:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT", 0, (spacing or 0)) - frame:SetPoint("BOTTOMRIGHT", anchor, "TOPRIGHT", 0, (spacing or 0)) - elseif position == "RIGHT" and anchor then - frame:SetPoint("TOPLEFT", anchor, "TOPRIGHT", (spacing or 0), 0) - frame:SetPoint("BOTTOMLEFT", anchor, "BOTTOMRIGHT", (spacing or 0), 0) - elseif position == "BOTTOM" and anchor then - frame:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -(spacing or 0)) - frame:SetPoint("TOPRIGHT", anchor, "BOTTOMRIGHT", 0, -(spacing or 0)) - elseif position == "LEFT" and anchor then - frame:SetPoint("TOPRIGHT", anchor, "TOPLEFT", -(spacing or 0), 0) - frame:SetPoint("BOTTOMRIGHT", anchor, "BOTTOMLEFT", -(spacing or 0), 0) - else - frame:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", 0, 0) - frame:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", 0, 0) - end + frame:ClearAllPoints() + if position == "TOP" and anchor then + frame:SetPoint("BOTTOMLEFT", anchor, "TOPLEFT", 0, (spacing or 0)) + frame:SetPoint("BOTTOMRIGHT", anchor, "TOPRIGHT", 0, (spacing or 0)) + elseif position == "RIGHT" and anchor then + frame:SetPoint("TOPLEFT", anchor, "TOPRIGHT", (spacing or 0), 0) + frame:SetPoint("BOTTOMLEFT", anchor, "BOTTOMRIGHT", (spacing or 0), 0) + elseif position == "BOTTOM" and anchor then + frame:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -(spacing or 0)) + frame:SetPoint("TOPRIGHT", anchor, "BOTTOMRIGHT", 0, -(spacing or 0)) + elseif position == "LEFT" and anchor then + frame:SetPoint("TOPRIGHT", anchor, "TOPLEFT", -(spacing or 0), 0) + frame:SetPoint("BOTTOMRIGHT", anchor, "BOTTOMLEFT", -(spacing or 0), 0) + else + frame:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", 0, 0) + frame:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", 0, 0) + end end -- [ SetAutoPoint ] @@ -738,68 +786,70 @@ end -- 'spacing' [number] the padding that should be used between the -- frame and its parent frame function pfUI.api.SetAutoPoint(frame, parent, spacing) - --[[ - - a b max - +-----------------+ - | 1 | 2 | 3 | - |-----+-----+-----| c - | 4 | 5 | 6 | - |-----+-----+-----| d - | 7 | 8 | 9 | - +-----------------+ - 0 - - ]]-- - - local a = GetScreenWidth() / 3 - local b = GetScreenWidth() / 3 * 2 - - local c = GetScreenHeight() / 3 * 2 - local d = GetScreenHeight() / 3 - - local x, y = parent:GetCenter() - - if not x or not y then return end - - local off = spacing or 0 - - frame:ClearAllPoints() - - if x < a and y > c then - -- TOPLEFT - frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", 0, -off) - elseif x > a and x < b and y > c then - -- TOP - frame:SetPoint("TOP", parent, "BOTTOM", 0, -off) - elseif x > b and y > c then - -- TOPRIGHT - frame:SetPoint("TOPRIGHT", parent, "BOTTOMRIGHT", 0, -off) - - elseif x < a and y > d and y < c then - -- LEFT - frame:SetPoint("LEFT", parent, "RIGHT", off, 0) - - elseif x > a and x < b and y > d and y < c then - -- CENTER - frame:SetPoint("BOTTOM", parent, "TOP", 0, off) - - elseif x > b and y > d and y < c then - -- RIGHT - frame:SetPoint("RIGHT", parent, "LEFT", -off, 0) + --[[ + + a b max + +-----------------+ + | 1 | 2 | 3 | + |-----+-----+-----| c + | 4 | 5 | 6 | + |-----+-----+-----| d + | 7 | 8 | 9 | + +-----------------+ + 0 + + ]]-- + + local a = GetScreenWidth() / 3 + local b = GetScreenWidth() / 3 * 2 + + local c = GetScreenHeight() / 3 * 2 + local d = GetScreenHeight() / 3 + + local x, y = parent:GetCenter() + + if not x or not y then + return + end - elseif x < a and y < d then - -- BOTTOMLEFT - frame:SetPoint("BOTTOMLEFT", parent, "TOPLEFT", 0, off) + local off = spacing or 0 - elseif x > a and x < b and y < d then - -- BOTTOM - frame:SetPoint("BOTTOM", parent, "TOP", 0, off) + frame:ClearAllPoints() - elseif x > b and y < d then - -- BOTTOMRIGHT - frame:SetPoint("BOTTOMRIGHT", parent, "TOPRIGHT", 0, off) - end + if x < a and y > c then + -- TOPLEFT + frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", 0, -off) + elseif x > a and x < b and y > c then + -- TOP + frame:SetPoint("TOP", parent, "BOTTOM", 0, -off) + elseif x > b and y > c then + -- TOPRIGHT + frame:SetPoint("TOPRIGHT", parent, "BOTTOMRIGHT", 0, -off) + + elseif x < a and y > d and y < c then + -- LEFT + frame:SetPoint("LEFT", parent, "RIGHT", off, 0) + + elseif x > a and x < b and y > d and y < c then + -- CENTER + frame:SetPoint("BOTTOM", parent, "TOP", 0, off) + + elseif x > b and y > d and y < c then + -- RIGHT + frame:SetPoint("RIGHT", parent, "LEFT", -off, 0) + + elseif x < a and y < d then + -- BOTTOMLEFT + frame:SetPoint("BOTTOMLEFT", parent, "TOPLEFT", 0, off) + + elseif x > a and x < b and y < d then + -- BOTTOM + frame:SetPoint("BOTTOM", parent, "TOP", 0, off) + + elseif x > b and y < d then + -- BOTTOMRIGHT + frame:SetPoint("BOTTOMRIGHT", parent, "TOPRIGHT", 0, off) + end end -- [ GetBestAnchor ] @@ -807,33 +857,35 @@ end -- 'self' [frame] the frame that should be checked -- returns: [string] the name of the best anchor function pfUI.api.GetBestAnchor(self) - local scale = self:GetScale() - local x, y = self:GetCenter() - local a = GetScreenWidth() / scale / 3 - local b = GetScreenWidth() / scale / 3 * 2 - local c = GetScreenHeight() / scale / 3 * 2 - local d = GetScreenHeight() / scale / 3 - if not x or not y then return end - - if x < a and y > c then - return "TOPLEFT" - elseif x > a and x < b and y > c then - return "TOP" - elseif x > b and y > c then - return "TOPRIGHT" - elseif x < a and y > d and y < c then - return "LEFT" - elseif x > a and x < b and y > d and y < c then - return "CENTER" - elseif x > b and y > d and y < c then - return "RIGHT" - elseif x < a and y < d then - return "BOTTOMLEFT" - elseif x > a and x < b and y < d then - return "BOTTOM" - elseif x > b and y < d then - return "BOTTOMRIGHT" - end + local scale = self:GetScale() + local x, y = self:GetCenter() + local a = GetScreenWidth() / scale / 3 + local b = GetScreenWidth() / scale / 3 * 2 + local c = GetScreenHeight() / scale / 3 * 2 + local d = GetScreenHeight() / scale / 3 + if not x or not y then + return + end + + if x < a and y > c then + return "TOPLEFT" + elseif x > a and x < b and y > c then + return "TOP" + elseif x > b and y > c then + return "TOPRIGHT" + elseif x < a and y > d and y < c then + return "LEFT" + elseif x > a and x < b and y > d and y < c then + return "CENTER" + elseif x > b and y > d and y < c then + return "RIGHT" + elseif x < a and y < d then + return "BOTTOMLEFT" + elseif x > a and x < b and y < d then + return "BOTTOM" + elseif x > b and y < d then + return "BOTTOMRIGHT" + end end -- [ ConvertFrameAnchor ] @@ -842,34 +894,34 @@ end -- 'anchor' [string] the new anchor that shall be used -- returns: anchor, x, y can directly be used in SetPoint() function pfUI.api.ConvertFrameAnchor(self, anchor) - local scale, x, y, _ = self:GetScale(), nil, nil, nil - - if anchor == "CENTER" then - x, y = self:GetCenter() - x, y = x - GetScreenWidth()/2/scale, y - GetScreenHeight()/2/scale - elseif anchor == "TOPLEFT" then - x, y = self:GetLeft(), self:GetTop() - GetScreenHeight()/scale - elseif anchor == "TOP" then - x, _ = self:GetCenter() - x, y = x - GetScreenWidth()/2/scale, self:GetTop() - GetScreenHeight()/scale - elseif anchor == "TOPRIGHT" then - x, y = self:GetRight() - GetScreenWidth()/scale, self:GetTop() - GetScreenHeight()/scale - elseif anchor == "RIGHT" then - _, y = self:GetCenter() - x, y = self:GetRight() - GetScreenWidth()/scale, y - GetScreenHeight()/2/scale - elseif anchor == "BOTTOMRIGHT" then - x, y = self:GetRight() - GetScreenWidth()/scale, self:GetBottom() - elseif anchor == "BOTTOM" then - x, _ = self:GetCenter() - x, y = x - GetScreenWidth()/2/scale, self:GetBottom() - elseif anchor == "BOTTOMLEFT" then - x, y = self:GetLeft(), self:GetBottom() - elseif anchor == "LEFT" then - _, y = self:GetCenter() - x, y = self:GetLeft(), y - GetScreenHeight()/2/scale - end - - return anchor, round(x, 2), round(y, 2) + local scale, x, y, _ = self:GetScale(), nil, nil, nil + + if anchor == "CENTER" then + x, y = self:GetCenter() + x, y = x - GetScreenWidth() / 2 / scale, y - GetScreenHeight() / 2 / scale + elseif anchor == "TOPLEFT" then + x, y = self:GetLeft(), self:GetTop() - GetScreenHeight() / scale + elseif anchor == "TOP" then + x, _ = self:GetCenter() + x, y = x - GetScreenWidth() / 2 / scale, self:GetTop() - GetScreenHeight() / scale + elseif anchor == "TOPRIGHT" then + x, y = self:GetRight() - GetScreenWidth() / scale, self:GetTop() - GetScreenHeight() / scale + elseif anchor == "RIGHT" then + _, y = self:GetCenter() + x, y = self:GetRight() - GetScreenWidth() / scale, y - GetScreenHeight() / 2 / scale + elseif anchor == "BOTTOMRIGHT" then + x, y = self:GetRight() - GetScreenWidth() / scale, self:GetBottom() + elseif anchor == "BOTTOM" then + x, _ = self:GetCenter() + x, y = x - GetScreenWidth() / 2 / scale, self:GetBottom() + elseif anchor == "BOTTOMLEFT" then + x, y = self:GetLeft(), self:GetBottom() + elseif anchor == "LEFT" then + _, y = self:GetCenter() + x, y = self:GetLeft(), y - GetScreenHeight() / 2 / scale + end + + return anchor, round(x, 2), round(y, 2) end -- [ GetStringColor ] @@ -877,11 +929,11 @@ end -- returns r,g,b,a local color_cache = {} function pfUI.api.GetStringColor(colorstr) - if not color_cache[colorstr] then - local r, g, b, a = pfUI.api.strsplit(",", colorstr) - color_cache[colorstr] = { r, g, b, a } - end - return unpack(color_cache[colorstr]) + if not color_cache[colorstr] then + local r, g, b, a = pfUI.api.strsplit(",", colorstr) + color_cache[colorstr] = { r, g, b, a } + end + return unpack(color_cache[colorstr]) end -- [ rgbhex ] @@ -893,52 +945,56 @@ end -- returns color string in the form of '|caarrggbb' local _r, _g, _b, _a function pfUI.api.rgbhex(r, g, b, a) - if type(r) == "table" then - if r.r then - _r, _g, _b, _a = r.r, r.g, r.b, (r.a or 1) - elseif table.getn(r) >= 3 then - _r, _g, _b, _a = r[1], r[2], r[3], (r[4] or 1) - end - elseif tonumber(r) then - _r, _g, _b, _a = r, g, b, (a or 1) - end - - if _r and _g and _b and _a then - -- limit values to 0-1 - _r = _r + 0 > 1 and 1 or _r + 0 - _g = _g + 0 > 1 and 1 or _g + 0 - _b = _b + 0 > 1 and 1 or _b + 0 - _a = _a + 0 > 1 and 1 or _a + 0 - return string.format("|c%02x%02x%02x%02x", _a*255, _r*255, _g*255, _b*255) - end - - return "" + if type(r) == "table" then + if r.r then + _r, _g, _b, _a = r.r, r.g, r.b, (r.a or 1) + elseif table.getn(r) >= 3 then + _r, _g, _b, _a = r[1], r[2], r[3], (r[4] or 1) + end + elseif tonumber(r) then + _r, _g, _b, _a = r, g, b, (a or 1) + end + + if _r and _g and _b and _a then + -- limit values to 0-1 + _r = _r + 0 > 1 and 1 or _r + 0 + _g = _g + 0 > 1 and 1 or _g + 0 + _b = _b + 0 > 1 and 1 or _b + 0 + _a = _a + 0 > 1 and 1 or _a + 0 + return string.format("|c%02x%02x%02x%02x", _a * 255, _r * 255, _g * 255, _b * 255) + end + + return "" end -- [ GetBorderSize ] -- Returns the configure value of a border and its pixel scaled version. -- 'pref' allows to specifiy a custom border (i.e unitframes, panel) function pfUI.api.GetBorderSize(pref) - if not pfUI.borders then pfUI.borders = {} end - - -- set to default border if accessing a wrong border type - if not pref or not pfUI_config.appearance.border[pref] or pfUI_config.appearance.border[pref] == "-1" then - pref = "default" - end - - if pfUI.borders[pref] then - -- return already cached values - return pfUI.borders[pref][1], pfUI.borders[pref][2] - else - -- add new borders to the pfUI tree - local raw = tonumber(pfUI_config.appearance.border[pref]) - if raw == -1 then raw = 3 end - - local scaled = raw * GetPerfectPixel() - pfUI.borders[pref] = { raw, scaled } - - return raw, scaled - end + if not pfUI.borders then + pfUI.borders = {} + end + + -- set to default border if accessing a wrong border type + if not pref or not pfUI_config.appearance.border[pref] or pfUI_config.appearance.border[pref] == "-1" then + pref = "default" + end + + if pfUI.borders[pref] then + -- return already cached values + return pfUI.borders[pref][1], pfUI.borders[pref][2] + else + -- add new borders to the pfUI tree + local raw = tonumber(pfUI_config.appearance.border[pref]) + if raw == -1 then + raw = 3 + end + + local scaled = raw * GetPerfectPixel() + pfUI.borders[pref] = { raw, scaled } + + return raw, scaled + end end -- [ GetPerfectPixel ] @@ -946,37 +1002,39 @@ end -- Respects the current UI-scale and calculates a real pixel based on -- the screen resolution and the 768px sized drawlayer. function pfUI.api.GetPerfectPixel() - if pfUI.pixel then return pfUI.pixel end + if pfUI.pixel then + return pfUI.pixel + end - if pfUI_config.appearance.border.pixelperfect == "1" then - local scale = GetCVar("uiScale") - local resolution = GetCVar("gxResolution") - local _, _, screenwidth, screenheight = strfind(resolution, "(.+)x(.+)") + if pfUI_config.appearance.border.pixelperfect == "1" then + local scale = GetCVar("uiScale") + local resolution = GetCVar("gxResolution") + local _, _, screenwidth, screenheight = strfind(resolution, "(.+)x(.+)") - pfUI.pixel = 768 / screenheight / scale - pfUI.pixel = pfUI.pixel > 1 and 1 or pfUI.pixel + pfUI.pixel = 768 / screenheight / scale + pfUI.pixel = pfUI.pixel > 1 and 1 or pfUI.pixel - -- autodetect and zoom for HiDPI displays - if pfUI_config.appearance.border.hidpi == "1" then - pfUI.pixel = pfUI.pixel < .5 and pfUI.pixel * 2 or pfUI.pixel + -- autodetect and zoom for HiDPI displays + if pfUI_config.appearance.border.hidpi == "1" then + pfUI.pixel = pfUI.pixel < .5 and pfUI.pixel * 2 or pfUI.pixel + end + else + pfUI.pixel = .7 end - else - pfUI.pixel = .7 - end - pfUI.backdrop = { - bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = false, tileSize = 0, - edgeFile = "Interface\\BUTTONS\\WHITE8X8", edgeSize = pfUI.pixel, - insets = {left = -pfUI.pixel, right = -pfUI.pixel, top = -pfUI.pixel, bottom = -pfUI.pixel}, - } + pfUI.backdrop = { + bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = false, tileSize = 0, + edgeFile = "Interface\\BUTTONS\\WHITE8X8", edgeSize = pfUI.pixel, + insets = { left = -pfUI.pixel, right = -pfUI.pixel, top = -pfUI.pixel, bottom = -pfUI.pixel }, + } - pfUI.backdrop_thin = { - bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = false, tileSize = 0, - edgeFile = "Interface\\BUTTONS\\WHITE8X8", edgeSize = pfUI.pixel, - insets = {left = 0, right = 0, top = 0, bottom = 0}, - } + pfUI.backdrop_thin = { + bgFile = "Interface\\BUTTONS\\WHITE8X8", tile = false, tileSize = 0, + edgeFile = "Interface\\BUTTONS\\WHITE8X8", edgeSize = pfUI.pixel, + insets = { left = 0, right = 0, top = 0, bottom = 0 }, + } - return pfUI.pixel + return pfUI.pixel end -- [ Create Backdrop ] @@ -987,134 +1045,144 @@ end -- 'transp' [number] set default transparency local backdrop, b, level, rawborder, border, br, bg, bb, ba, er, eg, eb, ea function pfUI.api.CreateBackdrop(f, inset, legacy, transp, backdropSetting) - -- exit if now frame was given - if not f then return end - - -- load raw and pixel perfect scaled border - rawborder, border = GetBorderSize() - - -- load custom border if existing - if inset then - rawborder = inset / GetPerfectPixel() - border = inset - end - - -- detect if blizzard backdrops shall be used - local blizz = C.appearance.border.force_blizz == "1" and true or nil - backdrop = blizz and pfUI.backdrop_blizz_full or rawborder == 1 and pfUI.backdrop_thin or pfUI.backdrop - border = blizz and math.max(border, 3) or border - - -- get the color settings - br, bg, bb, ba = pfUI.api.GetStringColor(pfUI_config.appearance.border.background) - er, eg, eb, ea = pfUI.api.GetStringColor(pfUI_config.appearance.border.color) - - if transp and transp < tonumber(ba) then ba = transp end - - -- use legacy backdrop handling - if legacy then - if backdropSetting then f:SetBackdrop(backdropSetting) end - f:SetBackdrop(backdrop) - f:SetBackdropColor(br, bg, bb, ba) - f:SetBackdropBorderColor(er, eg, eb , ea) - else - -- increase clickable area if available - if f.SetHitRectInsets and ( not InCombatLockdown or not InCombatLockdown()) then - f:SetHitRectInsets(-border,-border,-border,-border) - end - - -- use new backdrop behaviour - if not f.backdrop then - if f:GetBackdrop() then f:SetBackdrop(nil) end - - local b = CreateFrame("Frame", nil, f) - level = f:GetFrameLevel() - if level < 1 then - b:SetFrameLevel(level) - else - b:SetFrameLevel(level - 1) - end - - f.backdrop = b - end - - f.backdrop:SetPoint("TOPLEFT", f, "TOPLEFT", -border, border) - f.backdrop:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", border, -border) - f.backdrop:SetBackdrop(backdrop) - f.backdrop:SetBackdropColor(br, bg, bb, ba) - f.backdrop:SetBackdropBorderColor(er, eg, eb , ea) - - if blizz then - if not f.backdrop_border then - local border = CreateFrame("Frame", nil, f) - border:SetFrameLevel(level + 1) - f.backdrop_border = border - - local hookSetBackdropBorderColor = f.backdrop.SetBackdropBorderColor - f.backdrop.SetBackdropBorderColor = function(self, r, g, b, a) - f.backdrop_border:SetBackdropBorderColor(r, g, b, a) - hookSetBackdropBorderColor(f.backdrop, r, g, b, a) + -- exit if now frame was given + if not f then + return + end + + -- load raw and pixel perfect scaled border + rawborder, border = GetBorderSize() + + -- load custom border if existing + if inset then + rawborder = inset / GetPerfectPixel() + border = inset + end + + -- detect if blizzard backdrops shall be used + local blizz = C.appearance.border.force_blizz == "1" and true or nil + backdrop = blizz and pfUI.backdrop_blizz_full or rawborder == 1 and pfUI.backdrop_thin or pfUI.backdrop + border = blizz and math.max(border, 3) or border + + -- get the color settings + br, bg, bb, ba = pfUI.api.GetStringColor(pfUI_config.appearance.border.background) + er, eg, eb, ea = pfUI.api.GetStringColor(pfUI_config.appearance.border.color) + + if transp and transp < tonumber(ba) then + ba = transp + end + + -- use legacy backdrop handling + if legacy then + if backdropSetting then + f:SetBackdrop(backdropSetting) + end + f:SetBackdrop(backdrop) + f:SetBackdropColor(br, bg, bb, ba) + f:SetBackdropBorderColor(er, eg, eb, ea) + else + -- increase clickable area if available + if f.SetHitRectInsets and (not InCombatLockdown or not InCombatLockdown()) then + f:SetHitRectInsets(-border, -border, -border, -border) + end + + -- use new backdrop behaviour + if not f.backdrop then + if f:GetBackdrop() then + f:SetBackdrop(nil) + end + + local b = CreateFrame("Frame", nil, f) + level = f:GetFrameLevel() + if level < 1 then + b:SetFrameLevel(level) + else + b:SetFrameLevel(level - 1) + end + + f.backdrop = b end - end - f.backdrop_border:SetAllPoints(f.backdrop) - f.backdrop_border:SetBackdrop(pfUI.backdrop_blizz_border) - f.backdrop_border:SetBackdropBorderColor(er, eg, eb , ea) + f.backdrop:SetPoint("TOPLEFT", f, "TOPLEFT", -border, border) + f.backdrop:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", border, -border) + f.backdrop:SetBackdrop(backdrop) + f.backdrop:SetBackdropColor(br, bg, bb, ba) + f.backdrop:SetBackdropBorderColor(er, eg, eb, ea) + + if blizz then + if not f.backdrop_border then + local border = CreateFrame("Frame", nil, f) + border:SetFrameLevel(level + 1) + f.backdrop_border = border + + local hookSetBackdropBorderColor = f.backdrop.SetBackdropBorderColor + f.backdrop.SetBackdropBorderColor = function(self, r, g, b, a) + f.backdrop_border:SetBackdropBorderColor(r, g, b, a) + hookSetBackdropBorderColor(f.backdrop, r, g, b, a) + end + end + + f.backdrop_border:SetAllPoints(f.backdrop) + f.backdrop_border:SetBackdrop(pfUI.backdrop_blizz_border) + f.backdrop_border:SetBackdropBorderColor(er, eg, eb, ea) + end end - end end -- [ Create Shadow ] -- Creates a pfUI compatible frame as shadow element -- 'f' [frame] the frame which should get a backdrop. function pfUI.api.CreateBackdropShadow(f) - -- exit if now frame was given - if not f then return end - - if f.backdrop_shadow or pfUI_config.appearance.border.shadow ~= "1" then - return - end - - local anchor = f.backdrop or f - f.backdrop_shadow = CreateFrame("Frame", nil, anchor) - f.backdrop_shadow:SetFrameStrata("BACKGROUND") - f.backdrop_shadow:SetFrameLevel(1) - f.backdrop_shadow:SetPoint("TOPLEFT", anchor, "TOPLEFT", -7, 7) - f.backdrop_shadow:SetPoint("BOTTOMRIGHT", anchor, "BOTTOMRIGHT", 7, -7) - f.backdrop_shadow:SetBackdrop(pfUI.backdrop_shadow) - f.backdrop_shadow:SetBackdropBorderColor(0,0,0,tonumber(pfUI_config.appearance.border.shadow_intensity)) + -- exit if now frame was given + if not f then + return + end + + if f.backdrop_shadow or pfUI_config.appearance.border.shadow ~= "1" then + return + end + + local anchor = f.backdrop or f + f.backdrop_shadow = CreateFrame("Frame", nil, anchor) + f.backdrop_shadow:SetFrameStrata("BACKGROUND") + f.backdrop_shadow:SetFrameLevel(1) + f.backdrop_shadow:SetPoint("TOPLEFT", anchor, "TOPLEFT", -7, 7) + f.backdrop_shadow:SetPoint("BOTTOMRIGHT", anchor, "BOTTOMRIGHT", 7, -7) + f.backdrop_shadow:SetBackdrop(pfUI.backdrop_shadow) + f.backdrop_shadow:SetBackdropBorderColor(0, 0, 0, tonumber(pfUI_config.appearance.border.shadow_intensity)) end -- [ Bar Layout Options ] -- -- 'barsize' size of bar in number of buttons -- returns: array of options as strings for pfUI.gui.bar function pfUI.api.BarLayoutOptions(barsize) - assert(barsize > 0 and barsize <= NUM_ACTIONBAR_BUTTONS,"BarLayoutOptions: barsize "..tostring(barsize).." is invalid") - local options = {} - for i,layout in ipairs(pfGridmath[barsize]) do - options[i] = string.format("%d x %d",layout[1],layout[2]) - end - return options + assert(barsize > 0 and barsize <= NUM_ACTIONBAR_BUTTONS, "BarLayoutOptions: barsize " .. tostring(barsize) .. " is invalid") + local options = {} + for i, layout in ipairs(pfGridmath[barsize]) do + options[i] = string.format("%d x %d", layout[1], layout[2]) + end + return options end -- [ Bar Layout Formfactor ] -- -- 'option' string option as used in pfUI_config.bars[bar].option -- returns: integer formfactor local formfactors = {} -setmetatable(formfactors, {__mode = "v"}) -- weak table so values not referenced are collected on next gc +setmetatable(formfactors, { __mode = "v" }) -- weak table so values not referenced are collected on next gc function pfUI.api.BarLayoutFormfactor(option) - if formfactors[option] then - return formfactors[option] - else - for barsize,_ in ipairs(pfGridmath) do - local options = pfUI.api.BarLayoutOptions(barsize) - for i,opt in ipairs(options) do - if opt == option then - formfactors[option] = i - return formfactors[option] + if formfactors[option] then + return formfactors[option] + else + for barsize, _ in ipairs(pfGridmath) do + local options = pfUI.api.BarLayoutOptions(barsize) + for i, opt in ipairs(options) do + if opt == option then + formfactors[option] = i + return formfactors[option] + end + end end - end end - end end -- [ Bar Layout Size ] -- @@ -1122,14 +1190,14 @@ end -- 'barsize' integer number of buttons, -- 'formfactor' string formfactor in cols x rows, -- 'padding' the spacing between buttons -function pfUI.api.BarLayoutSize(bar,barsize,formfactor,iconsize,bordersize,padding) - assert(barsize > 0 and barsize <= NUM_ACTIONBAR_BUTTONS,"BarLayoutSize: barsize "..tostring(barsize).." is invalid") - local formfactor = pfUI.api.BarLayoutFormfactor(formfactor) - local cols, rows = unpack(pfGridmath[barsize][formfactor]) - local width = (iconsize + bordersize*2+padding) * cols + padding - local height = (iconsize + bordersize*2+padding) * rows + padding - bar._size = {width,height} - return bar._size +function pfUI.api.BarLayoutSize(bar, barsize, formfactor, iconsize, bordersize, padding) + assert(barsize > 0 and barsize <= NUM_ACTIONBAR_BUTTONS, "BarLayoutSize: barsize " .. tostring(barsize) .. " is invalid") + local formfactor = pfUI.api.BarLayoutFormfactor(formfactor) + local cols, rows = unpack(pfGridmath[barsize][formfactor]) + local width = (iconsize + bordersize * 2 + padding) * cols + padding + local height = (iconsize + bordersize * 2 + padding) * rows + padding + bar._size = { width, height } + return bar._size end -- [ Bar Button Anchor ] -- @@ -1140,72 +1208,80 @@ end -- 'iconsize' size of the button -- 'bordersize' default bordersize -- 'padding' the spacing between buttons -function pfUI.api.BarButtonAnchor(button,basename,buttonindex,barsize,formfactor,iconsize,bordersize,padding) - assert(barsize > 0 and barsize <= NUM_ACTIONBAR_BUTTONS,"BarButtonAnchor: barsize "..tostring(barsize).." is invalid") - local formfactor = pfUI.api.BarLayoutFormfactor(formfactor) - local parent = button:GetParent() - local cols, rows = unpack(pfGridmath[barsize][formfactor]) - if buttonindex == 1 then - button._anchor = {"TOPLEFT", parent, "TOPLEFT", bordersize+padding, -bordersize-padding} - else - local col = buttonindex-((math.ceil(buttonindex/cols)-1)*cols) - button._anchor = col==1 and {"TOP",_G[basename..(buttonindex-cols)],"BOTTOM",0,-(bordersize*2+padding)} or {"LEFT",_G[basename..(buttonindex-1)],"RIGHT",(bordersize*2+padding),0} - end - return button._anchor +function pfUI.api.BarButtonAnchor(button, basename, buttonindex, barsize, formfactor, iconsize, bordersize, padding) + assert(barsize > 0 and barsize <= NUM_ACTIONBAR_BUTTONS, "BarButtonAnchor: barsize " .. tostring(barsize) .. " is invalid") + local formfactor = pfUI.api.BarLayoutFormfactor(formfactor) + local parent = button:GetParent() + local cols, rows = unpack(pfGridmath[barsize][formfactor]) + if buttonindex == 1 then + button._anchor = { "TOPLEFT", parent, "TOPLEFT", bordersize + padding, -bordersize - padding } + else + local col = buttonindex - ((math.ceil(buttonindex / cols) - 1) * cols) + button._anchor = col == 1 and { "TOP", _G[basename .. (buttonindex - cols)], "BOTTOM", 0, -(bordersize * 2 + padding) } or { "LEFT", _G[basename .. (buttonindex - 1)], "RIGHT", (bordersize * 2 + padding), 0 } + end + return button._anchor end -- [ Enable Autohide ] -- -- 'frame' the frame that should be hidden function pfUI.api.EnableAutohide(frame, timeout, combat) - if not frame then return end - local timeout = timeout - - frame.hover = frame.hover or CreateFrame("Frame", frame:GetName() .. "Autohide", frame) - frame.hover:SetParent(frame) - frame.hover:SetAllPoints(frame) - frame.hover.parent = frame - frame.hover:Show() - - if combat then - frame.hover:RegisterEvent("PLAYER_REGEN_ENABLED") - frame.hover:RegisterEvent("PLAYER_REGEN_DISABLED") - frame.hover:SetScript("OnEvent", function() - if event == "PLAYER_REGEN_DISABLED" then - this.parent:SetAlpha(1) - this.activeTo = "keep" - elseif event == "PLAYER_REGEN_ENABLED" then - this.activeTo = GetTime() + timeout - end - end) - end - - frame.hover:SetScript("OnUpdate", function() - if this.activeTo == "keep" then return end - - if MouseIsOver(this, 10, -10, -10, 10) then - this.activeTo = GetTime() + timeout - this.parent:SetAlpha(1) - elseif this.activeTo then - if this.activeTo < GetTime() and this.parent:GetAlpha() > 0 then - local fps = (60 / math.max(GetFramerate(), 1)) - this.parent:SetAlpha(this.parent:GetAlpha() - 0.05*fps) - end - else - this.activeTo = GetTime() + timeout + if not frame then + return end - end) + local timeout = timeout + + frame.hover = frame.hover or CreateFrame("Frame", frame:GetName() .. "Autohide", frame) + frame.hover:SetParent(frame) + frame.hover:SetAllPoints(frame) + frame.hover.parent = frame + frame.hover:Show() + + if combat then + frame.hover:RegisterEvent("PLAYER_REGEN_ENABLED") + frame.hover:RegisterEvent("PLAYER_REGEN_DISABLED") + frame.hover:SetScript("OnEvent", function() + if event == "PLAYER_REGEN_DISABLED" then + this.parent:SetAlpha(1) + this.activeTo = "keep" + elseif event == "PLAYER_REGEN_ENABLED" then + this.activeTo = GetTime() + timeout + end + end) + end + + frame.hover:SetScript("OnUpdate", function() + if this.activeTo == "keep" then + return + end + + if MouseIsOver(this, 10, -10, -10, 10) then + this.activeTo = GetTime() + timeout + this.parent:SetAlpha(1) + elseif this.activeTo then + if this.activeTo < GetTime() and this.parent:GetAlpha() > 0 then + local fps = (60 / math.max(GetFramerate(), 1)) + this.parent:SetAlpha(this.parent:GetAlpha() - 0.05 * fps) + end + else + this.activeTo = GetTime() + timeout + end + end) end -- [ Disable Autohide ] -- -- 'frame' the frame that should get the autohide removed function pfUI.api.DisableAutohide(frame) - if not frame then return end - if not frame.hover then return end + if not frame then + return + end + if not frame.hover then + return + end - frame.hover:SetScript("OnEvent", nil) - frame.hover:SetScript("OnUpdate", nil) - frame.hover:Hide() - frame:SetAlpha(1) + frame.hover:SetScript("OnEvent", nil) + frame.hover:SetScript("OnUpdate", nil) + frame.hover:Hide() + frame:SetAlpha(1) end -- [ GetColoredTime ] -- @@ -1213,65 +1289,67 @@ end -- return a colored string including a time unit (m/h/d) local color_day, color_hour, color_minute, color_low, color_normal function pfUI.api.GetColoredTimeString(remaining) - if not remaining then return "" end - - -- Show days if remaining is > 99 Hours (99 * 60 * 60) - if remaining > 356400 then - if not color_day then - local r,g,b,a = pfUI.api.GetStringColor(C.appearance.cd.daycolor) - color_day = pfUI.api.rgbhex(r,g,b) + if not remaining then + return "" end - return color_day .. round(remaining / 86400) .. "|rd" + -- Show days if remaining is > 99 Hours (99 * 60 * 60) + if remaining > 356400 then + if not color_day then + local r, g, b, a = pfUI.api.GetStringColor(C.appearance.cd.daycolor) + color_day = pfUI.api.rgbhex(r, g, b) + end - -- Show hours if remaining is > 99 Minutes (99 * 60) - elseif remaining > 5940 then - if not color_hour then - local r,g,b,a = pfUI.api.GetStringColor(C.appearance.cd.hourcolor) - color_hour = pfUI.api.rgbhex(r,g,b) - end + return color_day .. round(remaining / 86400) .. "|rd" - return color_hour .. round(remaining / 3600) .. "|rh" + -- Show hours if remaining is > 99 Minutes (99 * 60) + elseif remaining > 5940 then + if not color_hour then + local r, g, b, a = pfUI.api.GetStringColor(C.appearance.cd.hourcolor) + color_hour = pfUI.api.rgbhex(r, g, b) + end - -- Show minutes if remaining is > 99 Seconds (99) - elseif remaining > 99 then - if not color_minute then - local r,g,b,a = pfUI.api.GetStringColor(C.appearance.cd.minutecolor) - color_minute = pfUI.api.rgbhex(r,g,b) - end + return color_hour .. round(remaining / 3600) .. "|rh" - return color_minute .. round(remaining / 60) .. "|rm" + -- Show minutes if remaining is > 99 Seconds (99) + elseif remaining > 99 then + if not color_minute then + local r, g, b, a = pfUI.api.GetStringColor(C.appearance.cd.minutecolor) + color_minute = pfUI.api.rgbhex(r, g, b) + end - -- Show milliseconds on low - elseif remaining <= 5 and pfUI_config.appearance.cd.milliseconds == "1" then - if not color_low then - local r,g,b,a = pfUI.api.GetStringColor(C.appearance.cd.lowcolor) - color_low = pfUI.api.rgbhex(r,g,b) - end + return color_minute .. round(remaining / 60) .. "|rm" - return color_low .. string.format("%.1f", round(remaining,1)) + -- Show milliseconds on low + elseif remaining <= 5 and pfUI_config.appearance.cd.milliseconds == "1" then + if not color_low then + local r, g, b, a = pfUI.api.GetStringColor(C.appearance.cd.lowcolor) + color_low = pfUI.api.rgbhex(r, g, b) + end - -- Show seconds on low - elseif remaining <= 5 then - if not color_low then - local r,g,b,a = pfUI.api.GetStringColor(C.appearance.cd.lowcolor) - color_low = pfUI.api.rgbhex(r,g,b) - end + return color_low .. string.format("%.1f", round(remaining, 1)) - return color_low .. round(remaining) + -- Show seconds on low + elseif remaining <= 5 then + if not color_low then + local r, g, b, a = pfUI.api.GetStringColor(C.appearance.cd.lowcolor) + color_low = pfUI.api.rgbhex(r, g, b) + end - -- Show seconds on normal - elseif remaining >= 0 then - if not color_normal then - local r, g, b, a = pfUI.api.GetStringColor(C.appearance.cd.normalcolor) - color_normal = pfUI.api.rgbhex(r,g,b) - end - return color_normal .. round(remaining) + return color_low .. round(remaining) - -- Return empty - else - return "" - end + -- Show seconds on normal + elseif remaining >= 0 then + if not color_normal then + local r, g, b, a = pfUI.api.GetStringColor(C.appearance.cd.normalcolor) + color_normal = pfUI.api.rgbhex(r, g, b) + end + return color_normal .. round(remaining) + + -- Return empty + else + return "" + end end -- [ GetColorGradient ] -- @@ -1279,37 +1357,37 @@ end -- return r,g,b and hexcolor local gradientcolors = {} function pfUI.api.GetColorGradient(perc) - perc = perc > 1 and 1 or perc - perc = perc < 0 and 0 or perc - perc = floor(perc*100)/100 - - local index = perc - if not gradientcolors[index] then - local r1, g1, b1, r2, g2, b2 - - if perc <= 0.5 then - perc = perc * 2 - r1, g1, b1 = 1, 0, 0 - r2, g2, b2 = 1, 1, 0 - else - perc = perc * 2 - 1 - r1, g1, b1 = 1, 1, 0 - r2, g2, b2 = 0, 1, 0 - end + perc = perc > 1 and 1 or perc + perc = perc < 0 and 0 or perc + perc = floor(perc * 100) / 100 + + local index = perc + if not gradientcolors[index] then + local r1, g1, b1, r2, g2, b2 + + if perc <= 0.5 then + perc = perc * 2 + r1, g1, b1 = 1, 0, 0 + r2, g2, b2 = 1, 1, 0 + else + perc = perc * 2 - 1 + r1, g1, b1 = 1, 1, 0 + r2, g2, b2 = 0, 1, 0 + end - local r = round(r1 + (r2 - r1) * perc, 4) - local g = round(g1 + (g2 - g1) * perc, 4) - local b = round(b1 + (b2 - b1) * perc, 4) - local h = pfUI.api.rgbhex(r,g,b) + local r = round(r1 + (r2 - r1) * perc, 4) + local g = round(g1 + (g2 - g1) * perc, 4) + local b = round(b1 + (b2 - b1) * perc, 4) + local h = pfUI.api.rgbhex(r, g, b) - gradientcolors[index] = {} - gradientcolors[index].r = r - gradientcolors[index].g = g - gradientcolors[index].b = b - gradientcolors[index].h = h - end + gradientcolors[index] = {} + gradientcolors[index].r = r + gradientcolors[index].g = g + gradientcolors[index].b = b + gradientcolors[index].h = h + end - return gradientcolors[index].r, + return gradientcolors[index].r, gradientcolors[index].g, gradientcolors[index].b, gradientcolors[index].h @@ -1323,47 +1401,102 @@ end -- 'arg1' [string] -- return object function pfUI.api.GetNoNameObject(frame, objtype, layer, arg1, arg2) - local arg1 = arg1 and gsub(arg1, "([%+%-%*%(%)%?%[%]%^])", "%%%1") - local arg2 = arg2 and gsub(arg2, "([%+%-%*%(%)%?%[%]%^])", "%%%1") - - local objects - if objtype == "Texture" or objtype == "FontString" then - objects = {frame:GetRegions()} - else - objects = {frame:GetChildren()} - end - - for _, object in ipairs(objects) do - local check = true - if object:GetObjectType() ~= objtype or (layer and object:GetDrawLayer() ~= layer) then check = false end - - if check then - if objtype == "Texture" and object.SetTexture and object:GetTexture() ~= "Interface\\BUTTONS\\WHITE8X8" then - if arg1 then - local texture = object:GetTexture() - if texture and not string.find(texture, arg1, 1) then check = false end - end + local arg1 = arg1 and gsub(arg1, "([%+%-%*%(%)%?%[%]%^])", "%%%1") + local arg2 = arg2 and gsub(arg2, "([%+%-%*%(%)%?%[%]%^])", "%%%1") - if check then return object end - elseif objtype == "FontString" and object.SetText then - if arg1 then - local text = object:GetText() - if text and not string.find(text, arg1, 1) then check = false end - end + local objects + if objtype == "Texture" or objtype == "FontString" then + objects = { frame:GetRegions() } + else + objects = { frame:GetChildren() } + end - if check then return object end - elseif objtype == "Button" and object.GetNormalTexture and object:GetNormalTexture() then - if arg1 then - local texture = object:GetNormalTexture():GetTexture() - if texture and not string.find(texture, arg1, 1) then check = false end - end - if arg2 then - local text = object:GetText() - if text and not string.find(text, arg2, 1) then check = false end + for _, object in ipairs(objects) do + local check = true + if object:GetObjectType() ~= objtype or (layer and object:GetDrawLayer() ~= layer) then + check = false end - if check then return object end - end + if check then + if objtype == "Texture" and object.SetTexture and object:GetTexture() ~= "Interface\\BUTTONS\\WHITE8X8" then + if arg1 then + local texture = object:GetTexture() + if texture and not string.find(texture, arg1, 1) then + check = false + end + end + + if check then + return object + end + elseif objtype == "FontString" and object.SetText then + if arg1 then + local text = object:GetText() + if text and not string.find(text, arg1, 1) then + check = false + end + end + + if check then + return object + end + elseif objtype == "Button" and object.GetNormalTexture and object:GetNormalTexture() then + if arg1 then + local texture = object:GetNormalTexture():GetTexture() + if texture and not string.find(texture, arg1, 1) then + check = false + end + end + if arg2 then + local text = object:GetText() + if text and not string.find(text, arg2, 1) then + check = false + end + end + + if check then + return object + end + end + end end - end end + +pfUI.api.PLAYER_BUFF_NOT_FOUND = pfUI.expansion == "vanilla" and -1 or 0 + +-- [ GetPlayerBuffX ] -- +-- +-- 'buffId' [number] The id of the buff to retrieve. Starts at 1 and can go up to at least 16. In turtle wow it can go up to 24. +-- Bare in mind that in Vanilla the GetPlayerBuff() method, that we are wrapping around, had 'buffId' being 0-based +-- and was changed to be 1-based in TBC. We enforce the TBC behavior here even in Vanilla for the sake of uniformity. +-- +-- 'buffFilter' [string] The "filter" to use when selecting buffs. Will affect what types of buffs are retrieved. Theoretically, it can +-- be any combination of HELPFUL, HARMFUL, PASSIVE, CANCELABLE, NOT_CANCELABLE according to comments in the source +-- code of the original GetPlayerBuff() we are wrapping around. +-- +-- return 'buffIndex', 'untilCancelled' +-- +-- 'buffIndex' [number] The index of the buff - if it's not found it will return 'pfUI.api.PLAYER_BUFF_NOT_FOUND' (which is -1 in Vanilla and 0 in TBC onwards) +-- 'untilCancelled' [number] If 1 this buff will last until it is cancelled (aura, aspect, stealth) +-- +-- Example of usage: +-- +-- for i=1,32,1 do +-- local buffIndex, untilCancelled = GetPlayerBuffX(i, "HELPFUL") +-- if buffIndex == pfUI.api.PLAYER_BUFF_NOT_FOUND then +-- [...handle buff not found...] +-- else +-- [...handle buff found...] +-- end +-- end +-- +pfUI.api.GetPlayerBuffX = pfUI.expansion == "vanilla" and (-- vanilla: + function(buffId, buffFilter) + + local buffIndex, untilCancelled = _G.GetPlayerBuff(buffId - 1, buffFilter) + + -- we intentionally leave 'buffIndex' as is (0-based) for Vanilla if we translate it into a 1-based index like in TBC we would + -- break the rest of the Vanilla API surface that expects 'buffIndex' to be 0-based in case of success and -1 in case of failure + return buffIndex, untilCancelled + end +) or _G.GetPlayerBuff -- tbc onwards From c09b6cc70a24cf9a1e98262b3798995a856fa271 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 22:00:52 +0200 Subject: [PATCH 09/70] refa (buff.lua, buffwatch.lua, unitframes.lua): use pfUI.api.GetPlayerBuffX() instead of GetPlayerBuff(PLAYER_BUFF_START_ID+...) --- api/unitframes.lua | 30 +++++++++++++++--------------- modules/buff.lua | 2 +- modules/buffwatch.lua | 6 +++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index a2b0ba579..7deec42f2 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -28,8 +28,8 @@ local glow2 = { local maxdurations = {} local function BuffOnUpdate() if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .2 end - local timeleft = GetPlayerBuffTimeLeft(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,"HELPFUL")) - local texture = GetPlayerBuffTexture(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,"HELPFUL")) + local timeleft = GetPlayerBuffTimeLeft(pfUI.api.GetPlayerBuffX(this.id,"HELPFUL")) + local texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(this.id,"HELPFUL")) local start = 0 if timeleft > 0 then @@ -59,13 +59,13 @@ local function BuffOnEnter() GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT") if parent.label == "player" then - GameTooltip:SetPlayerBuff(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,"HELPFUL")) + GameTooltip:SetPlayerBuff(pfUI.api.GetPlayerBuffX(this.id,"HELPFUL")) else GameTooltip:SetUnitBuff(parent.label .. parent.id, this.id) end if IsShiftKeyDown() then - local texture = parent.label == "player" and GetPlayerBuffTexture(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,"HELPFUL")) or UnitBuff(parent.label .. parent.id, this.id) + local texture = parent.label == "player" and GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(this.id,"HELPFUL")) or UnitBuff(parent.label .. parent.id, this.id) local playerlist = "" local first = true @@ -108,14 +108,14 @@ end local function BuffOnClick() if this:GetParent().label == "player" then - CancelPlayerBuff(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,"HELPFUL")) + CancelPlayerBuff(pfUI.api.GetPlayerBuffX(this.id,"HELPFUL")) end end local function DebuffOnUpdate() if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .2 end - local timeleft = GetPlayerBuffTimeLeft(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,"HARMFUL")) - local texture = GetPlayerBuffTexture(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,"HARMFUL")) + local timeleft = GetPlayerBuffTimeLeft(pfUI.api.GetPlayerBuffX(this.id,"HARMFUL")) + local texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(this.id,"HARMFUL")) local start = 0 if timeleft > 0 then @@ -135,7 +135,7 @@ local function DebuffOnEnter() GameTooltip:SetOwner(this, "ANCHOR_BOTTOMRIGHT") if this:GetParent().label == "player" then - GameTooltip:SetPlayerBuff(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,"HARMFUL")) + GameTooltip:SetPlayerBuff(pfUI.api.GetPlayerBuffX(this.id,"HARMFUL")) else GameTooltip:SetUnitDebuff(this:GetParent().label .. this:GetParent().id, this.id) end @@ -147,7 +147,7 @@ end local function DebuffOnClick() if this:GetParent().label == "player" then - CancelPlayerBuff(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,"HARMFUL")) + CancelPlayerBuff(pfUI.api.GetPlayerBuffX(this.id,"HARMFUL")) end end @@ -1480,8 +1480,8 @@ function pfUI.uf:RefreshUnit(unit, component) if not unit.buffs[i] then break end if unit.label == "player" then - stacks = GetPlayerBuffApplications(GetPlayerBuff(PLAYER_BUFF_START_ID+i,"HELPFUL")) - texture = GetPlayerBuffTexture(GetPlayerBuff(PLAYER_BUFF_START_ID+i,"HELPFUL")) + stacks = GetPlayerBuffApplications(pfUI.api.GetPlayerBuffX(i,"HELPFUL")) + texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(i,"HELPFUL")) else texture, stacks = pfUI.uf:DetectBuff(unitstr, i) end @@ -1552,9 +1552,9 @@ function pfUI.uf:RefreshUnit(unit, component) end if unit.label == "player" then - texture = GetPlayerBuffTexture(GetPlayerBuff(PLAYER_BUFF_START_ID+i, "HARMFUL")) - stacks = GetPlayerBuffApplications(GetPlayerBuff(PLAYER_BUFF_START_ID+i, "HARMFUL")) - dtype = GetPlayerBuffDispelType(GetPlayerBuff(PLAYER_BUFF_START_ID+i, "HARMFUL")) + texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(i, "HARMFUL")) + stacks = GetPlayerBuffApplications(pfUI.api.GetPlayerBuffX(i, "HARMFUL")) + dtype = GetPlayerBuffDispelType(pfUI.api.GetPlayerBuffX(i, "HARMFUL")) else texture, stacks, dtype = UnitDebuff(unitstr, i) end @@ -1571,7 +1571,7 @@ function pfUI.uf:RefreshUnit(unit, component) unit.debuffs[i]:Show() if unit:GetName() == "pfPlayer" then - local timeleft = GetPlayerBuffTimeLeft(GetPlayerBuff(PLAYER_BUFF_START_ID+unit.debuffs[i].id, "HARMFUL"),"HARMFUL") + local timeleft = GetPlayerBuffTimeLeft(pfUI.api.GetPlayerBuffX(unit.debuffs[i].id, "HARMFUL"),"HARMFUL") CooldownFrame_SetTimer(unit.debuffs[i].cd, GetTime(), timeleft, 1) elseif libdebuff then local name, rank, texture, stacks, dtype, duration, timeleft = libdebuff:UnitDebuff(unitstr, i) diff --git a/modules/buff.lua b/modules/buff.lua index 0cde0724f..514055a82 100644 --- a/modules/buff.lua +++ b/modules/buff.lua @@ -17,7 +17,7 @@ pfUI:RegisterModule("buff", "vanilla:tbc", function () else buff.id = buff.gid end - buff.bid = GetPlayerBuff(PLAYER_BUFF_START_ID+buff.id, buff.btype) + buff.bid = pfUI.api.GetPlayerBuffX(buff.id, buff.btype) if not buff.backdrop then CreateBackdrop(buff) diff --git a/modules/buffwatch.lua b/modules/buffwatch.lua index e6fc5280e..b18c0d7ad 100644 --- a/modules/buffwatch.lua +++ b/modules/buffwatch.lua @@ -76,7 +76,7 @@ pfUI:RegisterModule("buffwatch", "vanilla:tbc", function () local function GetBuffData(unit, id, type, skipTooltip) if unit == "player" then - local bid = GetPlayerBuff(PLAYER_BUFF_START_ID+id, type) + local bid = pfUI.api.GetPlayerBuffX(id, type) local stacks = GetPlayerBuffApplications(bid) local remaining = GetPlayerBuffTimeLeft(bid) local texture = GetPlayerBuffTexture(bid) @@ -112,7 +112,7 @@ pfUI:RegisterModule("buffwatch", "vanilla:tbc", function () DEFAULT_CHAT_FRAME:AddMessage("|cff33ffcc" .. skill .. "|r" .. T["is now blacklisted."]) end elseif this.parent.unit == "player" then - CancelPlayerBuff(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,this.type)) + CancelPlayerBuff(pfUI.api.GetPlayerBuffX(this.id,this.type)) end end @@ -120,7 +120,7 @@ pfUI:RegisterModule("buffwatch", "vanilla:tbc", function () GameTooltip:SetOwner(this, "NONE") if this.unit == "player" then - GameTooltip:SetPlayerBuff(GetPlayerBuff(PLAYER_BUFF_START_ID+this.id,this.type)) + GameTooltip:SetPlayerBuff(pfUI.api.GetPlayerBuffX(this.id,this.type)) elseif this.type == "HARMFUL" then GameTooltip:SetUnitDebuff(this.unit, this.id) elseif this.type == "HELPFUL" then From ef854151cf6a02a075419e8cd6281f78e81ee871 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 22:03:29 +0200 Subject: [PATCH 10/70] docs (api.lua): trivial doc-comment tweak --- api/api.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/api.lua b/api/api.lua index 2ab0c5839..551cf8685 100644 --- a/api/api.lua +++ b/api/api.lua @@ -1482,7 +1482,7 @@ pfUI.api.PLAYER_BUFF_NOT_FOUND = pfUI.expansion == "vanilla" and -1 or 0 -- Example of usage: -- -- for i=1,32,1 do --- local buffIndex, untilCancelled = GetPlayerBuffX(i, "HELPFUL") +-- local buffIndex, untilCancelled = pfUI.api.GetPlayerBuffX(i, "HELPFUL") -- if buffIndex == pfUI.api.PLAYER_BUFF_NOT_FOUND then -- [...handle buff not found...] -- else From 7ad1c43c45e11b1aa8c2da9e805a1ee3c1d7f5cf Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 22:04:51 +0200 Subject: [PATCH 11/70] feat (.gitignore) --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..62c893550 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ \ No newline at end of file From c3d0312449132adc13e2aef3cef26b6855fef242 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 22:05:38 +0200 Subject: [PATCH 12/70] feat (.luarc.json): this file configures the linter under Jetbrains' Rider --- .luarc.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .luarc.json diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 000000000..d283ec531 --- /dev/null +++ b/.luarc.json @@ -0,0 +1,7 @@ +{ + "diagnostics.disable": [ + "undefined-global", + "deprecated", + "cast-local-type" + ] +} \ No newline at end of file From ef424d9993fa97974b98224526db7279c61cc00c Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 1 Jun 2024 22:03:29 +0200 Subject: [PATCH 13/70] docs (api.lua): trivial doc-comment tweaks --- api/api.lua | 4 +++- compat/tbc.lua | 2 +- compat/vanilla.lua | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/api/api.lua b/api/api.lua index 2ab0c5839..4efb01b84 100644 --- a/api/api.lua +++ b/api/api.lua @@ -1482,11 +1482,13 @@ pfUI.api.PLAYER_BUFF_NOT_FOUND = pfUI.expansion == "vanilla" and -1 or 0 -- Example of usage: -- -- for i=1,32,1 do --- local buffIndex, untilCancelled = GetPlayerBuffX(i, "HELPFUL") +-- local buffIndex, untilCancelled = pfUI.api.GetPlayerBuffX(i, "HELPFUL") -- if buffIndex == pfUI.api.PLAYER_BUFF_NOT_FOUND then -- [...handle buff not found...] -- else -- [...handle buff found...] +-- +-- local buffTexture = GetPlayerBuffTexture(buffIndex) -- this simply works properly on both vanilla in tbc -- end -- end -- diff --git a/compat/tbc.lua b/compat/tbc.lua index 526d94bf5..e0f0fe8a4 100644 --- a/compat/tbc.lua +++ b/compat/tbc.lua @@ -27,7 +27,7 @@ FRIENDS_NAME_LOCATION = "ButtonTextLocation" COOLDOWN_FRAME_TYPE = "Cooldown" LOOT_BUTTON_FRAME_TYPE = "Button" -PLAYER_BUFF_START_ID = 0 +PLAYER_BUFF_START_ID = 0 -- deprecated kept around for 3rd party addons that might rely on it should be removed completely in the future ACTIONBAR_SECURE_TEMPLATE_BAR = "SecureStateHeaderTemplate" ACTIONBAR_SECURE_TEMPLATE_BUTTON = "SecureActionButtonTemplate" diff --git a/compat/vanilla.lua b/compat/vanilla.lua index 0cc4485f6..c27790daf 100644 --- a/compat/vanilla.lua +++ b/compat/vanilla.lua @@ -27,13 +27,14 @@ FRIENDS_NAME_LOCATION = "ButtonTextNameLocation" COOLDOWN_FRAME_TYPE = "Model" LOOT_BUTTON_FRAME_TYPE = "LootButton" -PLAYER_BUFF_START_ID = -1 +PLAYER_BUFF_START_ID = -1 -- deprecated kept around for 3rd party addons that might rely on it should be removed completely in the future ACTIONBAR_SECURE_TEMPLATE_BAR = nil ACTIONBAR_SECURE_TEMPLATE_BUTTON = nil UNITFRAME_SECURE_TEMPLATE = nil --[[ Vanilla API Extensions ]]-- + function hooksecurefunc(name, func, append) if not _G[name] then return end From 4b11bf2d28426789ec438d1ed34ed7b14f645a55 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 11:41:37 +0200 Subject: [PATCH 14/70] perf (unitframes.lua): optimize BuffOnUpdate() a bit by avoiding to call GetTime() twice --- api/unitframes.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index 7deec42f2..673464ede 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -27,7 +27,12 @@ local glow2 = { local maxdurations = {} local function BuffOnUpdate() - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .2 end + local now = GetTime() + if (this.tick or 1) > now then + return + end + + this.tick = now + .2 local timeleft = GetPlayerBuffTimeLeft(pfUI.api.GetPlayerBuffX(this.id,"HELPFUL")) local texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(this.id,"HELPFUL")) local start = 0 @@ -38,7 +43,8 @@ local function BuffOnUpdate() elseif maxdurations[texture] and maxdurations[texture] < timeleft then maxdurations[texture] = timeleft end - start = GetTime() + timeleft - maxdurations[texture] + + start = now + timeleft - maxdurations[texture] end CooldownFrame_SetTimer(this.cd, start, maxdurations[texture], timeleft > 0 and 1 or 0) From 523b900e20266d70d89ee73379bb891f427ec3fe Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 11:44:05 +0200 Subject: [PATCH 15/70] perf (unitframes.lua): BuffOnUpdate now calls pfUI.api.GetPlayerBuffX(this.id,"HELPFUL") --- api/unitframes.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index 673464ede..bc3c4dbbf 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -33,8 +33,10 @@ local function BuffOnUpdate() end this.tick = now + .2 - local timeleft = GetPlayerBuffTimeLeft(pfUI.api.GetPlayerBuffX(this.id,"HELPFUL")) - local texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(this.id,"HELPFUL")) + + local bid = pfUI.api.GetPlayerBuffX(this.id,"HELPFUL") + local timeleft = GetPlayerBuffTimeLeft(bid) + local texture = GetPlayerBuffTexture(bid) local start = 0 if timeleft > 0 then From 812893ffa2c90220b5d1b368c56d427e798368b2 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 11:47:01 +0200 Subject: [PATCH 16/70] perf (unitframes.lua): DebuffOnUpdate() now snapshots GetTime() once at the top of the call --- api/unitframes.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index bc3c4dbbf..e9823a1f6 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -121,7 +121,12 @@ local function BuffOnClick() end local function DebuffOnUpdate() - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .2 end + local now = GetTime() + if (this.tick or 1) > now then + return + end + + this.tick = now + .2 local timeleft = GetPlayerBuffTimeLeft(pfUI.api.GetPlayerBuffX(this.id,"HARMFUL")) local texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(this.id,"HARMFUL")) local start = 0 @@ -132,7 +137,8 @@ local function DebuffOnUpdate() elseif maxdurations[texture] and maxdurations[texture] < timeleft then maxdurations[texture] = timeleft end - start = GetTime() + timeleft - maxdurations[texture] + + start = now + timeleft - maxdurations[texture] end CooldownFrame_SetTimer(this.cd, start, maxdurations[texture], timeleft > 0 and 1 or 0) From e783d9bd8b31d6a316bd0793196a8c8ad85d840c Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 11:48:41 +0200 Subject: [PATCH 17/70] perf (unitframes.lua): DebuffOnUpdate() now calls GetPlayerBuffX() just once --- api/unitframes.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index e9823a1f6..3b4e01809 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -127,8 +127,9 @@ local function DebuffOnUpdate() end this.tick = now + .2 - local timeleft = GetPlayerBuffTimeLeft(pfUI.api.GetPlayerBuffX(this.id,"HARMFUL")) - local texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(this.id,"HARMFUL")) + local bid = pfUI.api.GetPlayerBuffX(this.id,"HARMFUL") + local timeleft = GetPlayerBuffTimeLeft(bid) + local texture = GetPlayerBuffTexture(bid) local start = 0 if timeleft > 0 then From 773934d5761a65c2f9bac4581dfb84790ddd3380 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 11:59:48 +0200 Subject: [PATCH 18/70] perf (unitframes.lua): call pfUI.api.GetPlayerBuffX(i,"HELPFUL") once in the 'buffs' section of :RefreshUnit() --- api/unitframes.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index 3b4e01809..14b02d27b 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -1489,14 +1489,15 @@ function pfUI.uf:RefreshUnit(unit, component) -- Buffs if unit.buffs and ( component == "all" or component == "aura" ) then - local texture, stacks + local texture, stacks, bid for i=1, unit.config.bufflimit do if not unit.buffs[i] then break end if unit.label == "player" then - stacks = GetPlayerBuffApplications(pfUI.api.GetPlayerBuffX(i,"HELPFUL")) - texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(i,"HELPFUL")) + bid = pfUI.api.GetPlayerBuffX(i,"HELPFUL") + stacks = GetPlayerBuffApplications(bid) + texture = GetPlayerBuffTexture(bid) else texture, stacks = pfUI.uf:DetectBuff(unitstr, i) end From 036f0c19aa7b9e186f38eb3a178865d80c2e7fcd Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 12:03:48 +0200 Subject: [PATCH 19/70] perf (unitframes.lua): call pfUI.api.GetPlayerBuffX(i,"HELPFUL") once per iteration inside the 'debuff' section of :RefreshUnit() --- api/unitframes.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index 14b02d27b..bddbf47f0 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -1556,6 +1556,7 @@ function pfUI.uf:RefreshUnit(unit, component) reposition = true end + local bid for i=1, unit.config.debufflimit do if not unit.debuffs[i] then break end @@ -1568,9 +1569,10 @@ function pfUI.uf:RefreshUnit(unit, component) end if unit.label == "player" then - texture = GetPlayerBuffTexture(pfUI.api.GetPlayerBuffX(i, "HARMFUL")) - stacks = GetPlayerBuffApplications(pfUI.api.GetPlayerBuffX(i, "HARMFUL")) - dtype = GetPlayerBuffDispelType(pfUI.api.GetPlayerBuffX(i, "HARMFUL")) + bid = pfUI.api.GetPlayerBuffX(i, "HARMFUL") + texture = GetPlayerBuffTexture(bid) + stacks = GetPlayerBuffApplications(bid) + dtype = GetPlayerBuffDispelType(bid) else texture, stacks, dtype = UnitDebuff(unitstr, i) end From 99fcfa094ce10fa76d76cb9ffc16a0f429793d38 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 12:05:53 +0200 Subject: [PATCH 20/70] perf (unitframes.lua): move the declaration of the 'row' variable outside the for-each-debuff loop of :RefreshUnit() --- api/unitframes.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index bddbf47f0..72766d168 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -1556,11 +1556,11 @@ function pfUI.uf:RefreshUnit(unit, component) reposition = true end - local bid + local row, bid for i=1, unit.config.debufflimit do if not unit.debuffs[i] then break end - local row = floor((i-1) / unit.config.debuffperrow) + row = floor((i-1) / unit.config.debuffperrow) if reposition then unit.debuffs[i]:SetPoint(af, unit, unit.config.debuffs, From 2147f6387bd02d919a8ebb3a3f292f02790877c4 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 12:45:31 +0200 Subject: [PATCH 21/70] perf (easteregg.lua): snapshot GetTime() once in each fireworks:SetScript("OnUpdate", ...) --- modules/easteregg.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/easteregg.lua b/modules/easteregg.lua index 35a76c6dc..ec057f2de 100644 --- a/modules/easteregg.lua +++ b/modules/easteregg.lua @@ -115,7 +115,12 @@ pfUI:RegisterModule("easteregg", "vanilla:tbc", function () local r,g,b = this.text:GetTextColor() this.text:SetTextColor(r+(math.random()-.5)/10, g+(math.random()-.5)/10, b+(math.random()-.5)/10,1) - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + math.random() - .2 end + local now = GetTime() + if (this.tick or 1) > now then + return + end + + this.tick = now + math.random() - .2 local x,y = math.random(1, width), -1*math.random(1,height) From fa37115f909a47e26e1d08f5e35ceb3c6c736677 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 12:47:46 +0200 Subject: [PATCH 22/70] perf (ui-widgets.lua): snapshot GetTime() once in each infobox:SetScript("OnUpdate", ...) --- api/ui-widgets.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/ui-widgets.lua b/api/ui-widgets.lua index fd2427899..4ecc912ae 100644 --- a/api/ui-widgets.lua +++ b/api/ui-widgets.lua @@ -1198,10 +1198,11 @@ function pfUI.api.CreateInfoBox(text, time, parent, height) infobox:Hide() infobox:SetScript("OnUpdate", function() - local time = infobox.lastshow + infobox.duration - GetTime() + local now = GetTime() + local time = infobox.lastshow + infobox.duration - now infobox.timeout:SetValue(time) - if GetTime() > infobox.lastshow + infobox.duration then + if now > infobox.lastshow + infobox.duration then infobox:SetAlpha(infobox:GetAlpha()-0.05) if infobox:GetAlpha() <= 0.1 then From 39377937c731d3c51e9cc5c78c5574f9d9275135 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 14:21:25 +0200 Subject: [PATCH 23/70] perf: snapshot GetTime() once per function-call so as to reuse the timestamp it generates --- api/unitframes.lua | 31 ++++++++++++++++++++++--------- libs/libdebuff.lua | 9 +++++---- libs/librange.lua | 7 ++++--- modules/actionbar.lua | 15 +++++++++++++-- modules/addonbuttons.lua | 7 ++++++- modules/addoncompat.lua | 7 ++++++- modules/afkcam.lua | 11 ++++++++--- modules/autovendor.lua | 7 ++++++- modules/bags.lua | 9 +++++++-- modules/buff.lua | 7 ++++--- modules/buffwatch.lua | 18 +++++++++++++----- modules/castbar.lua | 6 ++++-- modules/cooldown.lua | 13 +++++++++---- modules/energytick.lua | 9 ++++++--- modules/gui.lua | 7 ++++++- modules/hunterbar.lua | 10 ++++++++-- modules/infight.lua | 6 +++++- modules/mapcolors.lua | 6 ++++-- modules/minimap.lua | 7 ++++++- modules/nameplates.lua | 21 +++++++++++++-------- modules/panel.lua | 19 +++++++++++++------ modules/roll.lua | 5 +++-- modules/superwow.lua | 4 ++-- modules/totems.lua | 5 ++++- modules/xpbar.lua | 14 +++++++++++--- 25 files changed, 188 insertions(+), 72 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index a2b0ba579..a2223c9d0 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -154,18 +154,26 @@ end local visibilityscan = CreateFrame("Frame", "pfUnitFrameVisibility", UIParent) visibilityscan.frames = {} visibilityscan:SetScript("OnUpdate", function() - if ( this.limit or 1) > GetTime() then return else this.limit = GetTime() + .2 end - for frame in pairs(this.frames) do frame:UpdateVisibility() end + local now = GetTime() + if (this.limit or 1) > GetTime() then + return + end + + this.limit = now + .2 + for frame in pairs(this.frames) do + frame:UpdateVisibility() + end end) local aggrodata = { } function pfUI.api.UnitHasAggro(unit) - if aggrodata[unit] and GetTime() < aggrodata[unit].check + 1 then + local now = GetTime() + if aggrodata[unit] and now < aggrodata[unit].check + 1 then return aggrodata[unit].state end aggrodata[unit] = aggrodata[unit] or { } - aggrodata[unit].check = GetTime() + aggrodata[unit].check = now aggrodata[unit].state = 0 if UnitExists(unit) and UnitIsFriend(unit, "player") then @@ -1057,11 +1065,13 @@ function pfUI.uf.OnUpdate() end -- trigger eventless actions (online/offline/range) - if not this.lastTick then this.lastTick = GetTime() + (this.tick or .2) end - if this.lastTick and this.lastTick < GetTime() then + local now = GetTime() + if not this.lastTick then this.lastTick = now + (this.tick or .2) end + + if this.lastTick and this.lastTick < now then local unitstr = this.label .. this.id - this.lastTick = GetTime() + (this.tick or .2) + this.lastTick = now + (this.tick or .2) -- target target has a huge delay, make sure to not tick during range checks -- by waiting for a stable name over three ticks otherwise aborting the update. @@ -1540,6 +1550,7 @@ function pfUI.uf:RefreshUnit(unit, component) reposition = true end + local now for i=1, unit.config.debufflimit do if not unit.debuffs[i] then break end @@ -1572,11 +1583,13 @@ function pfUI.uf:RefreshUnit(unit, component) if unit:GetName() == "pfPlayer" then local timeleft = GetPlayerBuffTimeLeft(GetPlayerBuff(PLAYER_BUFF_START_ID+unit.debuffs[i].id, "HARMFUL"),"HARMFUL") - CooldownFrame_SetTimer(unit.debuffs[i].cd, GetTime(), timeleft, 1) + now = now or GetTime() + CooldownFrame_SetTimer(unit.debuffs[i].cd, now, timeleft, 1) elseif libdebuff then local name, rank, texture, stacks, dtype, duration, timeleft = libdebuff:UnitDebuff(unitstr, i) if duration and timeleft then - CooldownFrame_SetTimer(unit.debuffs[i].cd, GetTime() + timeleft - duration, duration, 1) + now = now or GetTime() + CooldownFrame_SetTimer(unit.debuffs[i].cd, now + timeleft - duration, duration, 1) end end diff --git a/libs/libdebuff.lua b/libs/libdebuff.lua index f9f9bacfb..4be322525 100644 --- a/libs/libdebuff.lua +++ b/libs/libdebuff.lua @@ -251,23 +251,24 @@ function libdebuff:UnitDebuff(unit, id) effect = scanner:Line(1) or "" end + local now = GetTime() if libdebuff.objects[unitname] and libdebuff.objects[unitname][unitlevel] and libdebuff.objects[unitname][unitlevel][effect] then -- clean up cache - if libdebuff.objects[unitname][unitlevel][effect].duration and libdebuff.objects[unitname][unitlevel][effect].duration + libdebuff.objects[unitname][unitlevel][effect].start < GetTime() then + if libdebuff.objects[unitname][unitlevel][effect].duration and libdebuff.objects[unitname][unitlevel][effect].duration + libdebuff.objects[unitname][unitlevel][effect].start < now then libdebuff.objects[unitname][unitlevel][effect] = nil else duration = libdebuff.objects[unitname][unitlevel][effect].duration - timeleft = duration + libdebuff.objects[unitname][unitlevel][effect].start - GetTime() + timeleft = duration + libdebuff.objects[unitname][unitlevel][effect].start - now end -- no level data elseif libdebuff.objects[unitname] and libdebuff.objects[unitname][0] and libdebuff.objects[unitname][0][effect] then -- clean up cache - if libdebuff.objects[unitname][0][effect].duration and libdebuff.objects[unitname][0][effect].duration + libdebuff.objects[unitname][0][effect].start < GetTime() then + if libdebuff.objects[unitname][0][effect].duration and libdebuff.objects[unitname][0][effect].duration + libdebuff.objects[unitname][0][effect].start < now then libdebuff.objects[unitname][0][effect] = nil else duration = libdebuff.objects[unitname][0][effect].duration - timeleft = duration + libdebuff.objects[unitname][0][effect].start - GetTime() + timeleft = duration + libdebuff.objects[unitname][0][effect].start - now end end diff --git a/libs/librange.lua b/libs/librange.lua index e8a4f962f..aa3e25690 100644 --- a/libs/librange.lua +++ b/libs/librange.lua @@ -147,12 +147,13 @@ local target_event = TargetFrame_OnEvent local target_nop = function() return end librange:SetScript("OnUpdate", function() - if ( this.tick or 1) > GetTime() then + local now = GetTime() + if (this.tick or 1) > now then return - else - this.tick = GetTime() + this.interval end + this.tick = now + this.interval + -- skip invalid units while not this:NeedRangeScan(units[this.id]) and this.id <= numunits do this.id = this.id + 1 diff --git a/modules/actionbar.lua b/modules/actionbar.lua index dae27954e..ef62aee74 100644 --- a/modules/actionbar.lua +++ b/modules/actionbar.lua @@ -810,7 +810,12 @@ pfUI:RegisterModule("actionbar", "vanilla:tbc", function () updatecache[id] = nil end - if ( this.tick or .2) > GetTime() then return else this.tick = GetTime() + .2 end + local now = GetTime() + if (this.tick or .2) > now then + return + end + + this.tick = now + .2 for id, button in pairs(buttoncache) do if button:IsShown() then ButtonRangeUpdate(button) end @@ -1651,7 +1656,13 @@ pfUI:RegisterModule("actionbar", "vanilla:tbc", function () -- queue events to fire only once per second if not this.event then return end - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 1 end + + local now = GetTime() + if (this.tick or 1) > now then + return + end + + this.tick = now + 1 -- scan for all reagent item counts for item in pairs(reagent_counts) do diff --git a/modules/addonbuttons.lua b/modules/addonbuttons.lua index d06c90924..d487d81c1 100644 --- a/modules/addonbuttons.lua +++ b/modules/addonbuttons.lua @@ -402,7 +402,12 @@ pfUI:RegisterModule("addonbuttons", "vanilla:tbc", function () pfUI.addonbuttons.scanner = CreateFrame("Frame", "pfAddonButtonScanner", UIParent) pfUI.addonbuttons.scanner:SetScript("OnUpdate", function() -- throttle updates to once per 3 seconds - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 3 end + local now = GetTime() + if (this.tick or 1) > now then + return + end + + this.tick = now + 3 pfUI.addonbuttons:ProcessButtons() for k, v in pairs(pfUI.addonbuttons.overrides) do diff --git a/modules/addoncompat.lua b/modules/addoncompat.lua index 3efefb618..9711effb2 100644 --- a/modules/addoncompat.lua +++ b/modules/addoncompat.lua @@ -136,7 +136,12 @@ pfUI:RegisterModule("addoncompat", function () local delay = CreateFrame("Frame") delay:SetScript("OnUpdate", function() -- throttle to to one query per .1 second - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .1 end + local now = GetTime() + if (this.tick or 1) > now then + return + end + + this.tick = now + .1 -- make sure the firstrun dialog has finished if pfUI.firstrun and pfUI.firstrun.steps then diff --git a/modules/afkcam.lua b/modules/afkcam.lua index 3ccca1119..8a58e7c23 100644 --- a/modules/afkcam.lua +++ b/modules/afkcam.lua @@ -163,7 +163,12 @@ pfUI:RegisterModule("afkcam", "vanilla:tbc", function () end) delay:SetScript("OnUpdate", function() - if ( this.tick or 0) > GetTime() then return else this.tick = GetTime() + 1 end + local now = GetTime() + if (this.tick or 0) > now then + return + end + + this.tick = now + 1 local name = UnitName("player") local cast = UnitCastingInfo(name) @@ -171,10 +176,10 @@ pfUI:RegisterModule("afkcam", "vanilla:tbc", function () if not this.delay then this.delay = 0 end if cast then - this.delay = GetTime() + 10 + this.delay = now + 10 end - if this.delay < GetTime() then + if this.delay < now then afkcam:start() this:Hide() end diff --git a/modules/autovendor.lua b/modules/autovendor.lua index 0f1169be8..251331312 100644 --- a/modules/autovendor.lua +++ b/modules/autovendor.lua @@ -46,7 +46,12 @@ pfUI:RegisterModule("autovendor", "vanilla:tbc", function () autovendor:SetScript("OnUpdate", function() -- throttle to to one item per .1 second - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .1 end + local now = GetTime() + if (this.tick or 1) > now then + return + end + + this.tick = now + .1 -- scan for the next grey item local bag, slot = GetNextGreyItem() diff --git a/modules/bags.lua b/modules/bags.lua index 0007f48da..ee15c94e0 100644 --- a/modules/bags.lua +++ b/modules/bags.lua @@ -75,8 +75,13 @@ pfUI:RegisterModule("bags", "vanilla:tbc", function () pfUI.bag.delay = { UpdateBag = {} } pfUI.bag:SetScript("OnUpdate", function() - -- update delayed ones every 0.1s - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .1 end + -- update delayed once every 0.1s + local now = GetTime() + if (this.tick or 1) > now then + return + end + + this.tick = now + .1 if this.delay.RefreshSpells then this.delay.RefreshSpells = nil diff --git a/modules/buff.lua b/modules/buff.lua index f71144169..1a2237039 100644 --- a/modules/buff.lua +++ b/modules/buff.lua @@ -120,9 +120,10 @@ pfUI:RegisterModule("buff", "vanilla:tbc", function () buff.gid = i buff:SetScript("OnUpdate", function() - if not this.next then this.next = GetTime() + .1 end - if this.next > GetTime() then return end - this.next = GetTime() + .1 + local now = GetTime() + if not this.next then this.next = now + .1 end + if this.next > now then return end + this.next = now + .1 local timeleft = 0 local stacks = 0 diff --git a/modules/buffwatch.lua b/modules/buffwatch.lua index e6fc5280e..62e761594 100644 --- a/modules/buffwatch.lua +++ b/modules/buffwatch.lua @@ -141,10 +141,13 @@ pfUI:RegisterModule("buffwatch", "vanilla:tbc", function () end local function StatusBarOnUpdate() - local remaining = this.endtime - GetTime() + local now = GetTime() + local remaining = this.endtime - now + this.bar:SetValue(remaining > 0 and remaining or 0) + if (this.tick or 1) > now then return end - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .1 end + this.tick = now + .1 this.time:SetText(remaining > 0 and GetColoredTimeString(remaining) or "") end @@ -250,7 +253,7 @@ pfUI:RegisterModule("buffwatch", "vanilla:tbc", function () table.sort(frame.buffs, frame.buffcmp) -- create a buff bar for each below threshold - local bar = 1 + local bar, now = 1, nil for id, data in pairs(frame.buffs) do if data[1] and ((data[1] ~= 0 and data[1] < frame.threshold) or frame.threshold == -1) -- timeleft checks and data[3] and data[3] ~= "" -- buff has a name @@ -263,7 +266,9 @@ pfUI:RegisterModule("buffwatch", "vanilla:tbc", function () frame.bars[bar].id = data[2] frame.bars[bar].unit = frame.unit frame.bars[bar].type = frame.type - frame.bars[bar].endtime = GetTime() + ( data[1] > 0 and data[1] or -1 ) + + now = now or GetTime() + frame.bars[bar].endtime = now + ( data[1] > 0 and data[1] or -1 ) -- update max duration the cached remaining values is less than -- the real one, indicates a buff renewal @@ -356,7 +361,10 @@ pfUI:RegisterModule("buffwatch", "vanilla:tbc", function () -- Create a new Buff Bar local function BuffBarFrameOnUpdate() - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .4 end + local now = GetTime() + if (this.tick or 1) > now then return end + + this.tick = now + .4 RefreshBuffBarFrame(this) this:RefreshPosition() end diff --git a/modules/castbar.lua b/modules/castbar.lua index 4a88fc328..c5fd6e9f2 100644 --- a/modules/castbar.lua +++ b/modules/castbar.lua @@ -102,7 +102,9 @@ pfUI:RegisterModule("castbar", "vanilla:tbc", function () if cast then local duration = endTime - startTime local max = duration / 1000 - local cur = GetTime() - startTime / 1000 + + local now = GetTime() + local cur = now - startTime / 1000 this:SetAlpha(1) @@ -139,7 +141,7 @@ pfUI:RegisterModule("castbar", "vanilla:tbc", function () end if channel then - cur = max + startTime/1000 - GetTime() + cur = max + startTime/1000 - now end cur = cur > max and max or cur diff --git a/modules/cooldown.lua b/modules/cooldown.lua index 43b8ef915..2f6da21a4 100644 --- a/modules/cooldown.lua +++ b/modules/cooldown.lua @@ -20,16 +20,21 @@ pfUI:RegisterModule("cooldown", "vanilla:tbc", function () end -- only run every 0.1 seconds from here on - if ( this.tick or .1) > GetTime() then return else this.tick = GetTime() + .1 end + local now = GetTime() + if (this.tick or .1) > now then + return + end + + this.tick = now + .1 -- fix own alpha value (should be inherited, but somehow isn't always) if this:GetAlpha() ~= parent:GetAlpha() then this:SetAlpha(parent:GetAlpha()) end - if this.start < GetTime() then + if this.start < now then -- calculating remaining time as it should be - local remaining = this.duration - (GetTime() - this.start) + local remaining = this.duration - (now - this.start) if remaining >= 0 then this.text:SetText(GetColoredTimeString(remaining)) else @@ -39,7 +44,7 @@ pfUI:RegisterModule("cooldown", "vanilla:tbc", function () -- I have absolutely no idea, but it works: -- https://github.com/Stanzilla/WoWUIBugs/issues/47 local time = time() - local startupTime = time - GetTime() + local startupTime = time - GetTime() --better not to use the variable 'now' here -- just a simplification of: ((2^32) - (start * 1000)) / 1000 local cdTime = (2 ^ 32) / 1000 - this.start local cdStartTime = startupTime - cdTime diff --git a/modules/energytick.lua b/modules/energytick.lua index 8e966afc8..d7570df59 100644 --- a/modules/energytick.lua +++ b/modules/energytick.lua @@ -45,17 +45,20 @@ pfUI:RegisterModule("energytick", "vanilla:tbc", function () end) energytick:SetScript("OnUpdate", function() + local now if this.target then - this.start, this.max = GetTime(), this.target + now = now or GetTime() + this.start, this.max = now, this.target this.target = nil end if not this.start then return end - this.current = GetTime() - this.start + now = now or GetTime() + this.current = now - this.start if this.current > this.max then - this.start, this.max, this.current = GetTime(), 2, 0 + this.start, this.max, this.current = now, 2, 0 end local pos = (C.unitframes.player.pwidth ~= "-1" and C.unitframes.player.pwidth or C.unitframes.player.width) * (this.current / this.max) diff --git a/modules/gui.lua b/modules/gui.lua index f3b49419a..c1b3038e6 100644 --- a/modules/gui.lua +++ b/modules/gui.lua @@ -1332,7 +1332,12 @@ pfUI:RegisterModule("gui", "vanilla:tbc", function () -- info updater local f = CreateFrame("Frame", nil, this) f:SetScript("OnUpdate", function() - if ( this.tick or 0) > GetTime() then return else this.tick = GetTime() + 1 end + local now = GetTime() + if (this.tick or 0) > now then + return + end + + this.tick = now + 1 local parent = this:GetParent() local localversion = tonumber(pfUI.version.major*10000 + pfUI.version.minor*100 + pfUI.version.fix) diff --git a/modules/hunterbar.lua b/modules/hunterbar.lua index af9b99ae1..2c90d44d8 100644 --- a/modules/hunterbar.lua +++ b/modules/hunterbar.lua @@ -14,8 +14,14 @@ pfUI:RegisterModule("hunterbar", "vanilla", function () pfUI.hunterbar:SetScript("OnEvent", function() if event == "PLAYER_ENTERING_WORLD" then this.event = GetTime() + 3 - elseif this.event and this.event < GetTime() + .2 then - this.event = GetTime() + .1 + return + end + + if this.event then + local now = GetTime() + if this.event < now + .2 then + this.event = now + .1 + end end end) diff --git a/modules/infight.lua b/modules/infight.lua index 95531a8ea..b62163708 100644 --- a/modules/infight.lua +++ b/modules/infight.lua @@ -1,7 +1,11 @@ pfUI:RegisterModule("infight", "vanilla:tbc", function () local function OnUpdate() if not this.infight and not this.aggro and not this.health then return end - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .1 end + + local now = GetTime() + if (this.tick or 1) > now then return end + + this.tick = now + .1 if not this.fadeValue then this.fadeValue = 1 end if this.fadeValue >= 0.3 then diff --git a/modules/mapcolors.lua b/modules/mapcolors.lua index d012d5e62..2331cc058 100644 --- a/modules/mapcolors.lua +++ b/modules/mapcolors.lua @@ -2,8 +2,10 @@ pfUI:RegisterModule("mapcolors", function () pfUI.mapcolors = CreateFrame("Frame", nil, UIParent) pfUI.mapcolors:SetScript("OnUpdate", function() - -- throttle to to one item per .1 second - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .1 end + local now = GetTime() -- throttle to one item per .1 second + if (this.tick or 1) > now then return end + + this.tick = now + .1 local frame, icon diff --git a/modules/minimap.lua b/modules/minimap.lua index 0e0ed2d52..f961b33af 100644 --- a/modules/minimap.lua +++ b/modules/minimap.lua @@ -109,7 +109,12 @@ pfUI:RegisterModule("minimap", "vanilla:tbc", function () pfUI.minimapCoordinates = CreateFrame("Frame", "pfMinimapCoord", pfUI.minimap) pfUI.minimapCoordinates:SetScript("OnUpdate", function() -- update coords every 0.1 seconds - if ( this.tick or .1) > GetTime() then return else this.tick = GetTime() + .1 end + local now = GetTime() + if (this.tick or .1) > now then + return + end + + this.tick = now + .1 this.posX, this.posY = GetPlayerMapPosition("player") if this.posX ~= 0 and this.posY ~= 0 then diff --git a/modules/nameplates.lua b/modules/nameplates.lua index 007964ec8..d0b0c6099 100644 --- a/modules/nameplates.lua +++ b/modules/nameplates.lua @@ -138,11 +138,13 @@ pfUI:RegisterModule("nameplates", "vanilla:tbc", function () local function PlateCacheDebuffs(self, unitstr, verify) if not self.debuffcache then self.debuffcache = {} end + local now for id = 1, 16 do local effect, _, texture, stacks, _, duration, timeleft = libdebuff:UnitDebuff(unitstr, id) if effect and timeleft then - local start = GetTime() - ( (duration or 0) - ( timeleft or 0) ) - local stop = GetTime() + ( timeleft or 0 ) + now = now or GetTime() + local start = now - ( (duration or 0) - ( timeleft or 0) ) + local stop = now + ( timeleft or 0 ) self.debuffcache[id] = self.debuffcache[id] or {} self.debuffcache[id].effect = effect self.debuffcache[id].texture = texture @@ -684,6 +686,7 @@ pfUI:RegisterModule("nameplates", "vanilla:tbc", function () end -- update all debuff icons + local now for i = 1, 16 do local effect, rank, texture, stacks, dtype, duration, timeleft if unitstr then @@ -712,7 +715,8 @@ pfUI:RegisterModule("nameplates", "vanilla:tbc", function () if duration and timeleft and debuffdurations then plate.debuffs[index].cd:SetAlpha(0) plate.debuffs[index].cd:Show() - CooldownFrame_SetTimer(plate.debuffs[index].cd, GetTime() + timeleft - duration, duration, 1) + now = now or GetTime() + CooldownFrame_SetTimer(plate.debuffs[index].cd, now + timeleft - duration, duration, 1) end index = index + 1 @@ -762,8 +766,9 @@ pfUI:RegisterModule("nameplates", "vanilla:tbc", function () end -- use timer based updates - if not nameplate.tick or nameplate.tick < GetTime() then - nameplate.tick = GetTime() + .2 + local now = GetTime() + if not nameplate.tick or nameplate.tick < now then + nameplate.tick = now + .2 update = true end @@ -810,7 +815,7 @@ pfUI:RegisterModule("nameplates", "vanilla:tbc", function () if nameplate.debuffcache then -- delete timed out caches for id, data in pairs(nameplate.debuffcache) do - if not data.stop or data.stop < GetTime() then + if not data.stop or data.stop < now then nameplate.debuffcache[id] = nil trigger = true end @@ -902,8 +907,8 @@ pfUI:RegisterModule("nameplates", "vanilla:tbc", function () elseif cast then local duration = endTime - startTime nameplate.castbar:SetMinMaxValues(0, duration/1000) - nameplate.castbar:SetValue(GetTime() - startTime/1000) - nameplate.castbar.text:SetText(round(startTime/1000 + duration/1000 - GetTime(),1)) + nameplate.castbar:SetValue(now - startTime/1000) + nameplate.castbar.text:SetText(round(startTime/1000 + duration/1000 - now,1)) if C.nameplates.spellname == "1" then nameplate.castbar.spell:SetText(cast) else diff --git a/modules/panel.lua b/modules/panel.lua index 75addf001..d0abe2785 100644 --- a/modules/panel.lua +++ b/modules/panel.lua @@ -59,7 +59,12 @@ pfUI:RegisterModule("panel", "vanilla:tbc", function() end end widget:SetScript("OnUpdate",function() - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 1 end + local now = GetTime() + if (this.tick or 1) > now then + return + end + + this.tick = now + 1 local h, m = GetGameTime() local noon = "AM" @@ -96,8 +101,9 @@ pfUI:RegisterModule("panel", "vanilla:tbc", function() widget.timerFrame.text:SetFont(font, font_size, "OUTLINE") widget.timerFrame.text:SetAllPoints(widget.timerFrame) widget.timerFrame:SetScript("OnUpdate", function() - if not widget.timerFrame.Snapshot then widget.timerFrame.Snapshot = GetTime() end - widget.timerFrame.curTime = SecondsToTime(floor(GetTime() - widget.timerFrame.Snapshot)) + local now = GetTime() + if not widget.timerFrame.Snapshot then widget.timerFrame.Snapshot = now end + widget.timerFrame.curTime = SecondsToTime(floor(now - widget.timerFrame.Snapshot)) if widget.timerFrame.curTime ~= "" then widget.timerFrame.text:SetText("|c33cccccc" .. widget.timerFrame.curTime) else @@ -128,10 +134,11 @@ pfUI:RegisterModule("panel", "vanilla:tbc", function() end end) widget.combat:SetScript("OnUpdate", function() - if not this.tick then this.tick = GetTime() end - if GetTime() <= this.tick + 1 then return else this.tick = GetTime() end + local now = GetTime() + if not this.tick then this.tick = now end + if now <= this.tick + 1 then return else this.tick = now end if this.combat then - pfUI.panel:OutputPanel("combat", "|cffffaaaa" .. SecondsToTime(ceil(GetTime() - this.combat))) + pfUI.panel:OutputPanel("combat", "|cffffaaaa" .. SecondsToTime(ceil(now - this.combat))) end end) end diff --git a/modules/roll.lua b/modules/roll.lua index 7762774c4..398182d67 100644 --- a/modules/roll.lua +++ b/modules/roll.lua @@ -45,13 +45,14 @@ pfUI:RegisterModule("roll", "vanilla:tbc", function () local itemName = GetItemInfo(itemLink) -- delete obsolete tables - if pfUI.roll.cache[itemName] and pfUI.roll.cache[itemName]["TIMESTAMP"] < GetTime() - 60 then + local now = GetTime() + if pfUI.roll.cache[itemName] and pfUI.roll.cache[itemName]["TIMESTAMP"] < now - 60 then pfUI.roll.cache[itemName] = nil end -- initialize itemtable if not pfUI.roll.cache[itemName] then - pfUI.roll.cache[itemName] = { ["GREED"] = {}, ["NEED"] = {}, ["PASS"] = {}, ["TIMESTAMP"] = GetTime() } + pfUI.roll.cache[itemName] = { ["GREED"] = {}, ["NEED"] = {}, ["PASS"] = {}, ["TIMESTAMP"] = now } end -- ignore already listed names diff --git a/modules/superwow.lua b/modules/superwow.lua index e44c9567f..7150dd441 100644 --- a/modules/superwow.lua +++ b/modules/superwow.lua @@ -7,7 +7,7 @@ pfUI:RegisterModule("superwow", "vanilla", function () if arg3 == "START" or arg3 == "CAST" or arg3 == "CHANNEL" then -- human readable argument list local guid = arg1 - local target = arg2 + -- local target = arg2 local event_type = arg3 local spell_id = arg4 local timer = arg5 @@ -27,7 +27,7 @@ pfUI:RegisterModule("superwow", "vanilla", function () if not libcast.db[guid] then libcast.db[guid] = {} end libcast.db[guid].cast = spell libcast.db[guid].rank = nil - libcast.db[guid].start = GetTime() + libcast.db[guid].start = start libcast.db[guid].casttime = timer libcast.db[guid].icon = icon libcast.db[guid].channel = event_type == "CHANNEL" or false diff --git a/modules/totems.lua b/modules/totems.lua index 59eab9732..dbf45dbcc 100644 --- a/modules/totems.lua +++ b/modules/totems.lua @@ -19,7 +19,10 @@ pfUI:RegisterModule("totems", "vanilla:tbc", function () -- there's no totem event in vanilla using ticks instead local eventemu = CreateFrame("Frame") eventemu:SetScript("OnUpdate", function() - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .5 end + local now = GetTime() + if (this.tick or 1) > now then return end + + this.tick = now + .5 totems:RefreshList() end) end diff --git a/modules/xpbar.lua b/modules/xpbar.lua index 97f91d61b..0eb740137 100644 --- a/modules/xpbar.lua +++ b/modules/xpbar.lua @@ -41,14 +41,16 @@ local function OnEnter(self) self:SetAlpha(1) if mode == "XP" then + local now = GetTime() + local xp, xpmax, exh = UnitXP("player"), UnitXPMax("player"), GetXPExhaustion() local xp_perc = round(xp / xpmax * 100) local remaining = xpmax - xp local remaining_perc = round(remaining / xpmax * 100) local exh_perc = GetXPExhaustion() and round(GetXPExhaustion() / xpmax * 100) or 0 - local xp_persec = ((xp - data.startxp)/(GetTime() - data.starttime)) + local xp_persec = ((xp - data.startxp)/(now - data.starttime)) local session = UnitXP("player") - data.startxp - local avg_hour = floor(((UnitXP("player") - data.startxp) / (GetTime() - data.starttime)) * 60 * 60) + local avg_hour = floor(((UnitXP("player") - data.startxp) / (now - data.starttime)) * 60 * 60) local time_remaining = xp_persec > 0 and SecondsToTime(remaining/xp_persec) or 0 -- fill gametooltip data @@ -117,7 +119,13 @@ end if self.always then return end if self:GetAlpha() == 0 or MouseIsOver(self) then return end - if ( self.tick or 1) > GetTime() then return else self.tick = GetTime() + .01 end + + local now = GetTime() + if (self.tick or 1) > now then + return + end + + self.tick = now + .01 self:SetAlpha(self:GetAlpha() - .05) end From 49a4e8f9639ad09c9f4b28cceb05356883d4ab0d Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 14:52:38 +0200 Subject: [PATCH 24/70] perf (panel.lua, unitframes.lua): snapshot GetTime() once per function-call so as to reuse the timestamp it generates --- api/unitframes.lua | 2 +- modules/panel.lua | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index a2223c9d0..62af5aa5b 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -155,7 +155,7 @@ local visibilityscan = CreateFrame("Frame", "pfUnitFrameVisibility", UIParent) visibilityscan.frames = {} visibilityscan:SetScript("OnUpdate", function() local now = GetTime() - if (this.limit or 1) > GetTime() then + if (this.limit or 1) > now then return end diff --git a/modules/panel.lua b/modules/panel.lua index d0abe2785..b3b7ccb91 100644 --- a/modules/panel.lua +++ b/modules/panel.lua @@ -185,8 +185,12 @@ pfUI:RegisterModule("panel", "vanilla:tbc", function() end end widget:SetScript("OnUpdate",function() - if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 1 end + local now = GetTime() + if (this.tick or 1) > now then + return + end + this.tick = now + 1 fps = floor(GetFramerate()) _, _, lag = GetNetStats() @@ -424,7 +428,12 @@ pfUI:RegisterModule("panel", "vanilla:tbc", function() end) widget:SetScript("OnUpdate",function() - if ( this.tick or 60) > GetTime() then return else this.tick = GetTime() + 60 end + local now = GetTime() + if (this.tick or 60) > now then + return + end + + this.tick = now + 60 if GetGuildInfo("player") then GuildRoster() end end) end From cc55da29dc0430dad16df675ea84ee6929252dc3 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 17:44:10 +0200 Subject: [PATCH 25/70] perf (libcast.lua): set lastcasttex from the return values of GetSpellInfo() --- libs/libcast.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 63036152c..a67b0b5b6 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -389,8 +389,10 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) - _, lastrank = libspell.GetSpellInfo(id, bookType) - lastcasttex = GetSpellTexture(id, bookType) + local _, rank, texture = libspell.GetSpellInfo(id, bookType) + + lastrank = rank + lastcasttex = texture if GetSpellCooldown(id, bookType) ~= 0 then local spellName = GetSpellName(id, bookType) From 1260f314b561cb7dcf883c9072e7e850206d258f Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 17:45:56 +0200 Subject: [PATCH 26/70] fix (libcast.lua): we now make sure that the given spell-id is in fact valid inside the CastSpell post-hook --- libs/libcast.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index a67b0b5b6..334cf691c 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -389,7 +389,8 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) - local _, rank, texture = libspell.GetSpellInfo(id, bookType) + local name, rank, texture, _, _, _, actualId = libspell.GetSpellInfo(id, bookType) + if not name or not actualId then return end -- ignore if the spell is not found lastrank = rank lastcasttex = texture From d91da23743285c51a741657898997508721c3b36 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 17:51:05 +0200 Subject: [PATCH 27/70] perf (libcast.lua): we now use the spell-name returned by GetSpellInfo() instead of re-querying GetSpellName() for it --- libs/libcast.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 334cf691c..b3a5f73af 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -389,14 +389,13 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) - local name, rank, texture, _, _, _, actualId = libspell.GetSpellInfo(id, bookType) - if not name or not actualId then return end -- ignore if the spell is not found + local spellName, rank, texture, _, _, _, actualId = libspell.GetSpellInfo(id, bookType) + if not spellName or not actualId then return end -- ignore if the spell is not found lastrank = rank lastcasttex = texture if GetSpellCooldown(id, bookType) ~= 0 then - local spellName = GetSpellName(id, bookType) CastCustom(spellName) end end, true) From 44f97b73856757574a926ff49fa61ff591fd5b3b Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 18:03:50 +0200 Subject: [PATCH 28/70] fix (libcast.lua): we now check that the id is valid (non-nil) to begin with --- libs/libcast.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/libcast.lua b/libs/libcast.lua index b3a5f73af..127d2cae3 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -389,6 +389,8 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) + if not id then return end + local spellName, rank, texture, _, _, _, actualId = libspell.GetSpellInfo(id, bookType) if not spellName or not actualId then return end -- ignore if the spell is not found From 65e5ec4c419d6e8df1c578b3ef7eb15b80e45cb4 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sun, 2 Jun 2024 18:04:16 +0200 Subject: [PATCH 29/70] fix (libcast.lua): we now healthcheck the given id against the one returned from GetSpellInfo too for good measure --- libs/libcast.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 127d2cae3..598a6f341 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -392,7 +392,7 @@ hooksecurefunc("CastSpell", function(id, bookType) if not id then return end local spellName, rank, texture, _, _, _, actualId = libspell.GetSpellInfo(id, bookType) - if not spellName or not actualId then return end -- ignore if the spell is not found + if not spellName or actualId ~= id then return end -- ignore if the spell is not found lastrank = rank lastcasttex = texture From 2def20352d5f410f9fb6122733a6dfc9bc46bd48 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Mon, 3 Jun 2024 23:56:59 +0200 Subject: [PATCH 30/70] refa (libcast.lua): actualId -> cachedId --- libs/libcast.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index b3a5f73af..aad032730 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -389,8 +389,8 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) - local spellName, rank, texture, _, _, _, actualId = libspell.GetSpellInfo(id, bookType) - if not spellName or not actualId then return end -- ignore if the spell is not found + local spellName, rank, texture, _, _, _, cachedId = libspell.GetSpellInfo(id, bookType) + if not spellName or not cachedId then return end -- ignore if the spell is not found lastrank = rank lastcasttex = texture From 59f595ce28d8794e2bbef06956b5a3b71aa5b8a7 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 00:08:47 +0200 Subject: [PATCH 31/70] perf (libcast.lua): in the "CastSpell" post-hook we now get the texture from .GetSpellInfo() directly - also introduce a guard-close in case the spell is phony - also use the spell-name returned by .GetSpellInfo() and pass it to CastCustom() thus saving us from making a separate call to GetSpellName() --- libs/libcast.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 63036152c..a1b3e825f 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -389,11 +389,13 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) - _, lastrank = libspell.GetSpellInfo(id, bookType) - lastcasttex = GetSpellTexture(id, bookType) + local spellName, rank, texture, _, _, _, cachedId = libspell.GetSpellInfo(id, bookType) + if not spellName or cachedId ~= id then return end -- ignore if the spell is not found + + lastrank = rank + lastcasttex = texture if GetSpellCooldown(id, bookType) ~= 0 then - local spellName = GetSpellName(id, bookType) CastCustom(spellName) end end, true) From e7008aeb383842136cc5656cfbf5fb00eafcbb14 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 00:21:29 +0200 Subject: [PATCH 32/70] perf (libcast.lua): we now set lastcasttex from the texture returned from libspell.GetSpellInfo() inside the "CastSpellByName" post-hook --- libs/libcast.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 63036152c..f4faf3ebd 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -399,7 +399,11 @@ hooksecurefunc("CastSpell", function(id, bookType) end, true) hooksecurefunc("CastSpellByName", function(spell, target) - _, lastrank = libspell.GetSpellInfo(spell) + local spellName, rank, texture, _, _, _, cachedId = libspell.GetSpellInfo(spell) + if not spellName or not cachedId then return end -- ignore if the spell is not found + + lastrank = rank + lastcasttex = texture for i=1,120 do -- detect if any cast is ongoing From d45afe9fd912cc97786a8da5dfee530135de889e Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 00:24:24 +0200 Subject: [PATCH 33/70] refa (libcast.lua): rename spell->spellCasted in the "CastSpellByName" post-hook this is to avoid the confusion against the var 'spell' defined at the top of the file --- libs/libcast.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index f4faf3ebd..b3cee5219 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -398,8 +398,8 @@ hooksecurefunc("CastSpell", function(id, bookType) end end, true) -hooksecurefunc("CastSpellByName", function(spell, target) - local spellName, rank, texture, _, _, _, cachedId = libspell.GetSpellInfo(spell) +hooksecurefunc("CastSpellByName", function(spellCasted, target) + local spellName, rank, texture, _, _, _, cachedId = libspell.GetSpellInfo(spellCasted) if not spellName or not cachedId then return end -- ignore if the spell is not found lastrank = rank @@ -408,7 +408,7 @@ hooksecurefunc("CastSpellByName", function(spell, target) for i=1,120 do -- detect if any cast is ongoing if IsCurrentAction(i) then - CastCustom(spell) + CastCustom(spellCasted) return end end From 69d6314ae67a64870e4bf1a4fd7fc6c0eb881931 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 00:08:47 +0200 Subject: [PATCH 34/70] perf (libcast.lua): in the "CastSpell" post-hook we now get the texture from .GetSpellInfo() directly - also introduce a guard-close in case the spell is phony - also use the spell-name returned by .GetSpellInfo() and pass it to CastCustom() thus saving us from making a separate call to GetSpellName() --- libs/libcast.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 63036152c..1d3239a12 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -389,12 +389,14 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) - _, lastrank = libspell.GetSpellInfo(id, bookType) - lastcasttex = GetSpellTexture(id, bookType) + local spellName, rank, texture, _, _, _, cachedId = libspell.GetSpellInfo(id, bookType) + if not spellName or not cachedId then return end -- ignore if the spell is not found + + lastrank = rank + lastcasttex = texture if GetSpellCooldown(id, bookType) ~= 0 then - local spellName = GetSpellName(id, bookType) - CastCustom(spellName) + CastCustom(spellName) end end, true) From f888d42e7c5a1b322ab556945e9bd8299cd6dbde Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 01:15:25 +0200 Subject: [PATCH 35/70] fix (libcast.lua): we now set lastcasttex from the texture returned by libspell.GetSpellInfo in "CastSpellByName" post-hook --- libs/libcast.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 63036152c..b3cee5219 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -398,13 +398,17 @@ hooksecurefunc("CastSpell", function(id, bookType) end end, true) -hooksecurefunc("CastSpellByName", function(spell, target) - _, lastrank = libspell.GetSpellInfo(spell) +hooksecurefunc("CastSpellByName", function(spellCasted, target) + local spellName, rank, texture, _, _, _, cachedId = libspell.GetSpellInfo(spellCasted) + if not spellName or not cachedId then return end -- ignore if the spell is not found + + lastrank = rank + lastcasttex = texture for i=1,120 do -- detect if any cast is ongoing if IsCurrentAction(i) then - CastCustom(spell) + CastCustom(spellCasted) return end end From 2bf3f1caa91905fdcb7c00e59ae7218bd9b222d5 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 01:44:38 +0200 Subject: [PATCH 36/70] refa (libcast.lua): move the GetSpellCooldown() check into CastCustom() and simplify the "CastSpell" check accordingly --- libs/libcast.lua | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index ff8aa1aed..2ae15a1bb 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -373,11 +373,12 @@ libcast.customcast[strlower(multishot)] = function(begin, duration) end end -local function CastCustom(spell) - if not spell then return end +local function CastCustom(id, bookType, rawSpellName) + if not rawSpellName or GetSpellCooldown(id, bookType) == 0 then return end + if not UnitCastingInfo(UnitName("player")) then for custom, func in pairs(libcast.customcast) do - if strfind(strlower(spell), custom) or strlower(spell) == custom then + if strfind(strlower(rawSpellName), custom) or strlower(rawSpellName) == custom then func(true) end end @@ -389,20 +390,18 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) - local spellName, rank, texture, _, _, _, cachedId = libspell.GetSpellInfo(id, bookType) - if not spellName or not cachedId then return end -- ignore if the spell is not found + local rawSpellName, rank, texture, _, _, _, cachedId, cachedBookType = libspell.GetSpellInfo(id, bookType) + if not rawSpellName or not cachedId then return end -- ignore if the spell is not found lastrank = rank lastcasttex = texture - if GetSpellCooldown(id, bookType) ~= 0 then - CastCustom(spellName) - end + CastCustom(cachedId, cachedBookType, rawSpellName) end, true) hooksecurefunc("CastSpellByName", function(spellCasted, target) - local spellName, rank, texture, _, _, _, cachedId = libspell.GetSpellInfo(spellCasted) - if not spellName or not cachedId then return end -- ignore if the spell is not found + local rawSpellName, rank, texture, _, _, _, cachedId, cachedBookType = libspell.GetSpellInfo(spellCasted) + if not rawSpellName or not cachedId then return end -- ignore if the spell is not found lastrank = rank lastcasttex = texture @@ -410,7 +409,7 @@ hooksecurefunc("CastSpellByName", function(spellCasted, target) for i=1,120 do -- detect if any cast is ongoing if IsCurrentAction(i) then - CastCustom(spellCasted) + CastCustom(cachedId, cachedBookType, rawSpellName) return end end From 5184a27a66466c5562a34a7c344808c0eb2e3058 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 01:48:10 +0200 Subject: [PATCH 37/70] perf (libcast.lua): simplify and optimize the "CastSpellByName" post-hook the loop 'for i=1,120' which was too taxing in cases where casts got spammed via macros that wouldn't activate any buttons in the actionbar causing the for loop to check every action bar only to end up empty-handed --- libs/libcast.lua | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 2ae15a1bb..4fde6cd35 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -406,13 +406,7 @@ hooksecurefunc("CastSpellByName", function(spellCasted, target) lastrank = rank lastcasttex = texture - for i=1,120 do - -- detect if any cast is ongoing - if IsCurrentAction(i) then - CastCustom(cachedId, cachedBookType, rawSpellName) - return - end - end + CastCustom(cachedId, cachedBookType, rawSpellName) end, true) hooksecurefunc("UseAction", function(slot, target, button) From 49ea28f6dceafebdc6bd035a038946865cf64473 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 01:50:22 +0200 Subject: [PATCH 38/70] perf (libcast.lua): cache strlower(rawSpellName) --- libs/libcast.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 4fde6cd35..2c9845306 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -374,13 +374,12 @@ libcast.customcast[strlower(multishot)] = function(begin, duration) end local function CastCustom(id, bookType, rawSpellName) - if not rawSpellName or GetSpellCooldown(id, bookType) == 0 then return end - - if not UnitCastingInfo(UnitName("player")) then - for custom, func in pairs(libcast.customcast) do - if strfind(strlower(rawSpellName), custom) or strlower(rawSpellName) == custom then - func(true) - end + if not rawSpellName or GetSpellCooldown(id, bookType) == 0 or UnitCastingInfo(player) then return end -- detect casting + + rawSpellName = strlower(rawSpellName) + for custom, func in pairs(libcast.customcast) do + if strfind(rawSpellName, custom) or strlower(rawSpellName) == custom then + func(true) end end end From eab9d25d2a9d75605fd12440857a6c60dc8ce928 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 01:56:33 +0200 Subject: [PATCH 39/70] perf (libcast.lua): simplify the if-condition inside the for-loop into a single check the 'or strlower(rawSpellName) == custom' is redundant --- libs/libcast.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 2c9845306..4e02dff3a 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -378,7 +378,7 @@ local function CastCustom(id, bookType, rawSpellName) rawSpellName = strlower(rawSpellName) for custom, func in pairs(libcast.customcast) do - if strfind(rawSpellName, custom) or strlower(rawSpellName) == custom then + if strfind(rawSpellName, custom) ~= nil then func(true) end end From 738b07f0c8677431c3a9b06145b2acb921e4410b Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 01:57:47 +0200 Subject: [PATCH 40/70] perf (libcast.lua): we now break immediately after finding the first matching libcast.customcast entry --- libs/libcast.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/libcast.lua b/libs/libcast.lua index 4e02dff3a..c6a906553 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -380,6 +380,7 @@ local function CastCustom(id, bookType, rawSpellName) for custom, func in pairs(libcast.customcast) do if strfind(rawSpellName, custom) ~= nil then func(true) + return end end end From 3c4d9cf9a6d33c3db4302f460e7af09b2d3d402b Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 22:16:53 +0200 Subject: [PATCH 41/70] fix (libcast.lua): adjust the "UseAction" post-hook to use the new flavour of CastCustom() --- libs/libcast.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index c6a906553..b0aa8f839 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -411,13 +411,18 @@ end, true) hooksecurefunc("UseAction", function(slot, target, button) scanner:SetAction(slot) - local spellName, rank = scanner:Line(1) + local rawSpellName, rank = scanner:Line(1) + if not rawSpellName then return end -- ignore if the spell is not found + + local cachedRawSpellName, cachedRank, cachedTexture, _, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(rawSpellName .. (rank and ("(" .. rank .. ")") or "")) + if not cachedRawSpellName or not cachedSpellId then return end -- ignore if the spell is not found - lastcasttex = GetActionTexture(slot) - lastrank = rank + lastrank = cachedRank + lastcasttex = cachedTexture if GetActionText(slot) or not IsCurrentAction(slot) then return end - CastCustom(spellName) + + CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName) end, true) -- add libcast to pfUI API From 217ab3ce03b07cd570d740a387313e2369964c6d Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 22:17:44 +0200 Subject: [PATCH 42/70] refa (libcast.lua): trivial neutral renames for the sake clarity in the post-hooks of "CastSpell" and "CastSpellByName" --- libs/libcast.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index b0aa8f839..1e2ca55cd 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -390,23 +390,23 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) - local rawSpellName, rank, texture, _, _, _, cachedId, cachedBookType = libspell.GetSpellInfo(id, bookType) - if not rawSpellName or not cachedId then return end -- ignore if the spell is not found + local cachedRawSpellName, cachedRank, cachedTexture, _, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(id, bookType) + if not cachedRawSpellName or not cachedSpellId then return end -- ignore if the spell is not found - lastrank = rank - lastcasttex = texture + lastrank = cachedRank + lastcasttex = cachedTexture - CastCustom(cachedId, cachedBookType, rawSpellName) + CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName) end, true) hooksecurefunc("CastSpellByName", function(spellCasted, target) - local rawSpellName, rank, texture, _, _, _, cachedId, cachedBookType = libspell.GetSpellInfo(spellCasted) - if not rawSpellName or not cachedId then return end -- ignore if the spell is not found + local cachedRawSpellName, cachedRank, cachedTexture, _, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(spellCasted) + if not cachedRawSpellName or not cachedSpellId then return end -- ignore if the spell is not found - lastrank = rank - lastcasttex = texture + lastrank = cachedRank + lastcasttex = cachedTexture - CastCustom(cachedId, cachedBookType, rawSpellName) + CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName) end, true) hooksecurefunc("UseAction", function(slot, target, button) From 80a2d99f53e0007935a5c64b28a72886a5099732 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 4 Jun 2024 22:20:15 +0200 Subject: [PATCH 43/70] perf (libcast.lua): CastCustom() has been optimized to simply use libcast.customcast as a mere lookup-table instead of iterating over all of its entries one by one --- libs/libcast.lua | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 1e2ca55cd..62adc6b4e 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -375,14 +375,11 @@ end local function CastCustom(id, bookType, rawSpellName) if not rawSpellName or GetSpellCooldown(id, bookType) == 0 or UnitCastingInfo(player) then return end -- detect casting + + local func = libcast.customcast[strlower(rawSpellName)] + if not func then return end - rawSpellName = strlower(rawSpellName) - for custom, func in pairs(libcast.customcast) do - if strfind(rawSpellName, custom) ~= nil then - func(true) - return - end - end + func(true) end hooksecurefunc("UseContainerItem", function(id, index) From e60da93f4fa62b6939f9c189ed37b155096961e1 Mon Sep 17 00:00:00 2001 From: Artur Morozov Date: Wed, 5 Jun 2024 02:46:44 +0300 Subject: [PATCH 44/70] mapcolors: add data caching --- modules/mapcolors.lua | 83 +++++++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/modules/mapcolors.lua b/modules/mapcolors.lua index e97610fe1..aa9bf19c8 100644 --- a/modules/mapcolors.lua +++ b/modules/mapcolors.lua @@ -1,49 +1,86 @@ -- adds class colored circles on world and battlefield map pfUI:RegisterModule("mapcolors", function () + local button_cache = {} local function Initialize(unit_button_name) local texture_size = tonumber(C.appearance.worldmap.groupcircles) for i=1, MAX_PARTY_MEMBERS do - local frame = _G[unit_button_name.."Party"..i] - frame.icon = _G[unit_button_name.."Party"..i.."Icon"] + local frame_name = unit_button_name.."Party"..i + local frame = _G[frame_name] + frame.icon = _G[frame_name.."Icon"] frame.icon:SetTexture(pfUI.media["img:circleparty"]) frame.icon:SetVertexColor(.5, 1, .5) SetAllPointsOffset(frame.icon, frame, texture_size, -texture_size) + -- populate cache to default values + button_cache[frame_name] = { + r = .5, g = 1, b = .5 + } end for i=1, MAX_RAID_MEMBERS do - local frame = _G[unit_button_name.."Raid"..i] - frame.icon = _G[unit_button_name.."Raid"..i.."Icon"] + local frame_name = unit_button_name.."Raid"..i + local frame = _G[frame_name] + frame.icon = _G[frame_name.."Icon"] frame.icon:SetTexture(pfUI.media["img:circleraid"]) frame.icon:SetVertexColor(.5, 1, .5) SetAllPointsOffset(frame.icon, frame, texture_size, -texture_size) + -- populate cache to default values + button_cache[frame_name] = { + inParty = false, + r = .5, g = 1, b = .5 + } end end - local function UpdateTexture(frame) - if UnitInParty(frame.unit) then - frame.icon:SetTexture(pfUI.media["img:circleparty"]) - else - frame.icon:SetTexture(pfUI.media["img:circleraid"]) - end - end - local function UpdateTextureColor(frame) + local function GetTextureColor(frame) if UnitExists(frame.unit) then local _, class = UnitClass(frame.unit) local color = RAID_CLASS_COLORS[class] - frame.icon:SetVertexColor(color.r, color.g, color.b) + return color.r, color.g, color.b else - frame.icon:SetVertexColor(.5, 1, .5) + return .5, 1, .5 end end + local function UpdateTexture(frame, inParty) + print('UpdateTexture', frame:GetName(), frame.unit, UnitName(frame.unit), UnitClass(frame.unit), inParty) + if inParty then + frame.icon:SetTexture(pfUI.media["img:circleparty"]) + else + frame.icon:SetTexture(pfUI.media["img:circleraid"]) + end + end + local function UpdateTextureColor(frame, r, g, b) + print('UpdateTextureColor', frame:GetName(), frame.unit, UnitName(frame.unit), UnitClass(frame.unit), r, g, b) + frame.icon:SetVertexColor(r, g, b) + end local function UpdateUnitFrames(unit_button_name) if GetNumRaidMembers() > 0 then for i=1, MAX_RAID_MEMBERS do - local frame = _G[unit_button_name.."Raid"..i] - UpdateTexture(frame) - UpdateTextureColor(frame) + local frame_name = unit_button_name.."Raid"..i + local frame = _G[frame_name] + local cache = button_cache[frame_name] + if frame.unit then + local inParty = UnitInParty(frame.unit) + if inParty ~= cache.inParty then + cache.inParty = inParty + UpdateTexture(frame, cache.inParty) + end + local r, g, b = GetTextureColor(frame) + if r ~= cache.r or g ~= cache.g or b ~= cache.b then + cache.r, cache.g, cache.b = r, g, b + UpdateTextureColor(frame, cache.r, cache.g, cache.b) + end + end end elseif GetNumPartyMembers() > 0 then for i=1, MAX_PARTY_MEMBERS do - local frame = _G[unit_button_name.."Party"..i] - UpdateTextureColor(frame) + local frame_name = unit_button_name.."Party"..i + local frame = _G[frame_name] + local cache = button_cache[frame_name] + if frame.unit then + local r, g, b = GetTextureColor(frame) + if r ~= cache.r or g ~= cache.g or b ~= cache.b then + cache.r, cache.g, cache.b = r, g, b + UpdateTextureColor(frame, cache.r, cache.g, cache.b) + end + end end end end @@ -85,10 +122,14 @@ pfUI:RegisterModule("mapcolors", function () -- WorldMap Initialize('WorldMap') hooksecurefunc('WorldMapButton_OnUpdate', function() + -- throttle to to one item per 1 second + if ( this.tick or .5) > GetTime() then return else this.tick = GetTime() + .5 end UpdateUnitFrames('WorldMap') end) if C.appearance.worldmap.colornames == "1" then hooksecurefunc('WorldMapUnit_OnEnter', function() + -- throttle to to one item per 1 second + if ( this.tick or .5) > GetTime() then return else this.tick = GetTime() + .5 end UpdateUnitColors('WorldMap', WorldMapTooltip) end) end @@ -96,10 +137,14 @@ pfUI:RegisterModule("mapcolors", function () HookAddonOrVariable("Blizzard_BattlefieldMinimap", function() Initialize('BattlefieldMinimap') hooksecurefunc('BattlefieldMinimap_OnUpdate', function() + -- throttle to to one item per 1 second + if ( this.tick or .5) > GetTime() then return else this.tick = GetTime() + .5 end UpdateUnitFrames('BattlefieldMinimap') end) if C.appearance.worldmap.colornames == "1" then hooksecurefunc('BattlefieldMinimapUnit_OnEnter', function() + -- throttle to to one item per 1 second + if ( this.tick or .5) > GetTime() then return else this.tick = GetTime() + .5 end UpdateUnitColors('BattlefieldMinimap', GameTooltip) end) end From d20af9a34f88607cdfa0b8b58907bfe1d1a6a191 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Wed, 5 Jun 2024 18:25:56 +0200 Subject: [PATCH 45/70] refa (libcast.lua): further consolidate CastCustom() so that it will ignore any spell that is instant-cast setting lastrank and lastcasttex now happens inside CastCustom() --- libs/libcast.lua | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 62adc6b4e..257329a95 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -373,8 +373,13 @@ libcast.customcast[strlower(multishot)] = function(begin, duration) end end -local function CastCustom(id, bookType, rawSpellName) - if not rawSpellName or GetSpellCooldown(id, bookType) == 0 or UnitCastingInfo(player) then return end -- detect casting +local function CastCustom(id, bookType, rawSpellName, rank, texture, castingTime) + if not id or not rawSpellName or not castingTime then return end -- ignore if the spell is not found or if it is instant-cast + + lastrank = rank + lastcasttex = texture + + if GetSpellCooldown(id, bookType) == 0 or UnitCastingInfo("player") then return end -- detect casting local func = libcast.customcast[strlower(rawSpellName)] if not func then return end @@ -387,23 +392,15 @@ hooksecurefunc("UseContainerItem", function(id, index) end) hooksecurefunc("CastSpell", function(id, bookType) - local cachedRawSpellName, cachedRank, cachedTexture, _, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(id, bookType) - if not cachedRawSpellName or not cachedSpellId then return end -- ignore if the spell is not found - - lastrank = cachedRank - lastcasttex = cachedTexture + local cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(id, bookType) - CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName) + CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime) end, true) hooksecurefunc("CastSpellByName", function(spellCasted, target) - local cachedRawSpellName, cachedRank, cachedTexture, _, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(spellCasted) - if not cachedRawSpellName or not cachedSpellId then return end -- ignore if the spell is not found + local cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(spellCasted) - lastrank = cachedRank - lastcasttex = cachedTexture - - CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName) + CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime) end, true) hooksecurefunc("UseAction", function(slot, target, button) @@ -411,15 +408,11 @@ hooksecurefunc("UseAction", function(slot, target, button) local rawSpellName, rank = scanner:Line(1) if not rawSpellName then return end -- ignore if the spell is not found - local cachedRawSpellName, cachedRank, cachedTexture, _, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(rawSpellName .. (rank and ("(" .. rank .. ")") or "")) - if not cachedRawSpellName or not cachedSpellId then return end -- ignore if the spell is not found - - lastrank = cachedRank - lastcasttex = cachedTexture + local cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(rawSpellName .. (rank and ("(" .. rank .. ")") or "")) if GetActionText(slot) or not IsCurrentAction(slot) then return end - CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName) + CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime) end, true) -- add libcast to pfUI API From 89ed35125361852808420aa0389badf246014ab5 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Wed, 5 Jun 2024 18:49:50 +0200 Subject: [PATCH 46/70] perf (libcast.lua): we now guard-close immediately inside the "UseAction" post-hook if we detect that the given slot is not the currently active one --- libs/libcast.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 257329a95..35d3b4c4f 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -404,13 +404,13 @@ hooksecurefunc("CastSpellByName", function(spellCasted, target) end, true) hooksecurefunc("UseAction", function(slot, target, button) + if GetActionText(slot) or not IsCurrentAction(slot) then return end + scanner:SetAction(slot) local rawSpellName, rank = scanner:Line(1) if not rawSpellName then return end -- ignore if the spell is not found - - local cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(rawSpellName .. (rank and ("(" .. rank .. ")") or "")) - if GetActionText(slot) or not IsCurrentAction(slot) then return end + local cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(rawSpellName .. (rank and ("(" .. rank .. ")") or "")) CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime) end, true) From 3973faa55e9462750811d41fa27c0f5214245e75 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Wed, 5 Jun 2024 19:41:12 +0200 Subject: [PATCH 47/70] perf (libcast.lua): in CastCustom() we now "detect casting" check after we have established that we do in fact have func() to run for the particular spell --- libs/libcast.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 35d3b4c4f..b6a0fe410 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -378,13 +378,13 @@ local function CastCustom(id, bookType, rawSpellName, rank, texture, castingTime lastrank = rank lastcasttex = texture - - if GetSpellCooldown(id, bookType) == 0 or UnitCastingInfo("player") then return end -- detect casting - + local func = libcast.customcast[strlower(rawSpellName)] if not func then return end - func(true) + if GetSpellCooldown(id, bookType) == 0 or UnitCastingInfo(player) then return end -- detect casting + + func(true) end hooksecurefunc("UseContainerItem", function(id, index) From cb86b7964340aa46666d1be93127562d4a7113df Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Wed, 5 Jun 2024 20:25:37 +0200 Subject: [PATCH 48/70] perf (libcast.lua): introduce GetCustomCastFunc() which checks whether the currently cast spell was the same as the previous one and handle that in a special way --- libs/libcast.lua | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index b6a0fe410..9eea49d44 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -373,18 +373,26 @@ libcast.customcast[strlower(multishot)] = function(begin, duration) end end +local lastRawSpellName, lastfunc +local function GetCustomCastFunc(spellName) + -- to ultra-optimize cases in which paladins spam 'flash of light' all the time this allows us to skip strlower + table lookup completely + if rawequal(lastRawSpellName, rawSpellName) then return lastfunc end + + lastRawSpellName = rawSpellName + + return libcast.customcast[strlower(spellName)] +end + local function CastCustom(id, bookType, rawSpellName, rank, texture, castingTime) if not id or not rawSpellName or not castingTime then return end -- ignore if the spell is not found or if it is instant-cast lastrank = rank lastcasttex = texture - local func = libcast.customcast[strlower(rawSpellName)] - if not func then return end - - if GetSpellCooldown(id, bookType) == 0 or UnitCastingInfo(player) then return end -- detect casting + lastfunc = GetCustomCastFunc(rawSpellName) + if not lastfunc or GetSpellCooldown(id, bookType) == 0 or UnitCastingInfo(player) then return end -- detect casting - func(true) + lastfunc(true) end hooksecurefunc("UseContainerItem", function(id, index) From 55a3eabd80e358af3c517e85e751fac3d5408b70 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Thu, 6 Jun 2024 20:47:59 +0200 Subject: [PATCH 49/70] refa (libcast.lua): simplify the way we call libspell.GetSpellInfo() inside the "UseAction" post-hook --- libs/libcast.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 9eea49d44..5ed73f5e6 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -418,7 +418,7 @@ hooksecurefunc("UseAction", function(slot, target, button) local rawSpellName, rank = scanner:Line(1) if not rawSpellName then return end -- ignore if the spell is not found - local cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(rawSpellName .. (rank and ("(" .. rank .. ")") or "")) + local cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(rawSpellName, rank) CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime) end, true) From 9103240c15b9f15e57af04bbc48ee012eef95311 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Thu, 6 Jun 2024 21:06:23 +0200 Subject: [PATCH 50/70] fix (libspell.lua): GetSpellIndex() now caches spells with a properly formatted key-name --- libs/libspell.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/libspell.lua b/libs/libspell.lua index f7fa4a146..6176c84f0 100644 --- a/libs/libspell.lua +++ b/libs/libspell.lua @@ -46,8 +46,8 @@ end -- return: [number],[string] spell index and spellbook id local spellindex = {} function libspell.GetSpellIndex(name, rank) - local name = string.lower(name) - local cache = spellindex[name..(rank or "")] + name = string.lower(name) + local cache = spellindex[name..(rank and ("("..rank..")") or "")] if cache then return cache[1], cache[2] end if not rank then rank = libspell.GetSpellMaxRank(name) end @@ -58,7 +58,7 @@ function libspell.GetSpellIndex(name, rank) for id = offset + 1, offset + num do local spellName, spellRank = GetSpellName(id, bookType) if rank and rank == spellRank and name == string.lower(spellName) then - spellindex[name..rank] = { id, bookType } + spellindex[name.."("..rank..")"] = { id, bookType } return id, bookType elseif not rank and name == string.lower(spellName) then spellindex[name] = { id, bookType } @@ -67,7 +67,7 @@ function libspell.GetSpellIndex(name, rank) end end - spellindex[name..(rank or "")] = { nil } + spellindex[name..(rank and ("("..rank..")") or "")] = { nil } return nil end From a0bc7297089e4758d88507e783fbb8da992bcf59 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 8 Jun 2024 12:07:02 +0200 Subject: [PATCH 51/70] fix (libcast.lua): fix the way libspell.GetSpellInfo() is invoked inside hooksecurefunc("UseAction") --- libs/libcast.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 5ed73f5e6..9eea49d44 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -418,7 +418,7 @@ hooksecurefunc("UseAction", function(slot, target, button) local rawSpellName, rank = scanner:Line(1) if not rawSpellName then return end -- ignore if the spell is not found - local cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(rawSpellName, rank) + local cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime, _, _, cachedSpellId, cachedBookType = libspell.GetSpellInfo(rawSpellName .. (rank and ("(" .. rank .. ")") or "")) CastCustom(cachedSpellId, cachedBookType, cachedRawSpellName, cachedRank, cachedTexture, cachedCastingTime) end, true) From 5510d3ac2a66cb0c6841223f5e89684411f1ff49 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Sat, 8 Jun 2024 13:57:14 +0200 Subject: [PATCH 52/70] fix (libcast.lua): fix a bug which was preventing GetCustomCastFunc() from guard-closing upon detecting that the spell being cast is the one used last time --- libs/libcast.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/libcast.lua b/libs/libcast.lua index 9eea49d44..7eae1f03f 100644 --- a/libs/libcast.lua +++ b/libs/libcast.lua @@ -374,13 +374,13 @@ libcast.customcast[strlower(multishot)] = function(begin, duration) end local lastRawSpellName, lastfunc -local function GetCustomCastFunc(spellName) +local function GetCustomCastFunc(rawSpellName) -- to ultra-optimize cases in which paladins spam 'flash of light' all the time this allows us to skip strlower + table lookup completely if rawequal(lastRawSpellName, rawSpellName) then return lastfunc end lastRawSpellName = rawSpellName - return libcast.customcast[strlower(spellName)] + return libcast.customcast[strlower(rawSpellName)] end local function CastCustom(id, bookType, rawSpellName, rank, texture, castingTime) From bc74eb0b016961982707adbdea0acb0e74e08387 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 11 Jun 2024 00:46:04 +0200 Subject: [PATCH 53/70] perf (libdebuff.lua): in the post-hooks of CastSpell and CastSpellByName we now get the raw-effect name from the 1st returned argument of libspell.GetSpellInfo() --- libs/libdebuff.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libs/libdebuff.lua b/libs/libdebuff.lua index f9f9bacfb..1bde95197 100644 --- a/libs/libdebuff.lua +++ b/libs/libdebuff.lua @@ -218,16 +218,15 @@ end) -- Gather Data by User Actions hooksecurefunc("CastSpell", function(id, bookType) - local effect = GetSpellName(id, bookType) - local _, rank = libspell.GetSpellInfo(id, bookType) - local duration = libdebuff:GetDuration(effect, rank) - libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration) + local rawEffect, rank = libspell.GetSpellInfo(id, bookType) + local duration = libdebuff:GetDuration(rawEffect, rank) + libdebuff:AddPending(UnitName("target"), UnitLevel("target"), rawEffect, duration) end, true) hooksecurefunc("CastSpellByName", function(effect, target) - local _, rank = libspell.GetSpellInfo(effect) - local duration = libdebuff:GetDuration(effect, rank) - libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration) + local rawEffect, rank = libspell.GetSpellInfo(effect) + local duration = libdebuff:GetDuration(rawEffect, rank) + libdebuff:AddPending(UnitName("target"), UnitLevel("target"), rawEffect, duration) end, true) hooksecurefunc("UseAction", function(slot, target, button) From 12e5b9415a4d60ccd681dcbd9b7c846cf2292283 Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 11 Jun 2024 00:48:34 +0200 Subject: [PATCH 54/70] perf (libdebuff.lua): AddPending() now checks for duration <= 0 first as a guard-close in the same vein of thought when duration proves to be positive we no longer fallback to 'or libdebuff:GetDuration(effect)' --- libs/libdebuff.lua | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/libs/libdebuff.lua b/libs/libdebuff.lua index 1bde95197..be8ab2814 100644 --- a/libs/libdebuff.lua +++ b/libs/libdebuff.lua @@ -75,15 +75,13 @@ function libdebuff:UpdateUnits() end function libdebuff:AddPending(unit, unitlevel, effect, duration) - if not unit then return end - if not L["debuffs"][effect] then return end - - if duration > 0 and libdebuff.pending[3] ~= effect then - libdebuff.pending[1] = unit - libdebuff.pending[2] = unitlevel or 0 - libdebuff.pending[3] = effect - libdebuff.pending[4] = duration or libdebuff:GetDuration(effect) - end + if not unit or duration <= 0 then return end + if not L["debuffs"][effect] or libdebuff.pending[3] == effect then return end + + libdebuff.pending[1] = unit + libdebuff.pending[2] = unitlevel or 0 + libdebuff.pending[3] = effect + libdebuff.pending[4] = duration -- or libdebuff:GetDuration(effect) end function libdebuff:RemovePending() From 6c47468cd6d07a25da8e64a80cf700e7c496cb6a Mon Sep 17 00:00:00 2001 From: "D. Sidiropoulos" Date: Tue, 11 Jun 2024 00:49:26 +0200 Subject: [PATCH 55/70] refa (libdebuff.lua): trivial renames to align the naming conventions used in the "UseAction" post-hook vs the other 2 post-hooks --- libs/libdebuff.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/libdebuff.lua b/libs/libdebuff.lua index be8ab2814..afac1df2a 100644 --- a/libs/libdebuff.lua +++ b/libs/libdebuff.lua @@ -230,9 +230,9 @@ end, true) hooksecurefunc("UseAction", function(slot, target, button) if GetActionText(slot) or not IsCurrentAction(slot) then return end scanner:SetAction(slot) - local effect, rank = scanner:Line(1) - local duration = libdebuff:GetDuration(effect, rank) - libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration) + local rawEffect, rank = scanner:Line(1) + local duration = libdebuff:GetDuration(rawEffect, rank) + libdebuff:AddPending(UnitName("target"), UnitLevel("target"), rawEffect, duration) end, true) function libdebuff:UnitDebuff(unit, id) From 7895de1ec517b3acad1bfabc6847c9af6b7c7ce3 Mon Sep 17 00:00:00 2001 From: Kyriakos Sidiropoulos Date: Mon, 14 Apr 2025 01:24:04 +0200 Subject: [PATCH 56/70] fix (nameplates.lua): fix a bug which was causing a runtime error because the 'now' variable was not being set --- modules/nameplates.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/nameplates.lua b/modules/nameplates.lua index 6b9884b5b..e593c4d8a 100644 --- a/modules/nameplates.lua +++ b/modules/nameplates.lua @@ -938,8 +938,9 @@ pfUI:RegisterModule("nameplates", "vanilla:tbc", function () end -- scan for debuff timeouts + local now = GetTime() if nameplate.debuffcache then - for id, data in pairs(nameplate.debuffcache) do + for _, data in pairs(nameplate.debuffcache) do if ( not data.stop or data.stop < now ) and not data.empty then data.empty = true update = true From c0b48c788b6839d66633dbc7ca0f971c558e3dfe Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Thu, 24 Apr 2025 18:16:35 +0200 Subject: [PATCH 57/70] chore (.gitignore): introduce a gitignore file --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..62c893550 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ \ No newline at end of file From 7fe38422a3be01b50a8f029ad5bfaa8f50af9649 Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Mon, 5 May 2025 21:32:05 +0200 Subject: [PATCH 58/70] add Folder.DotSettings for user dictionary configuration --- Folder.DotSettings | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Folder.DotSettings diff --git a/Folder.DotSettings b/Folder.DotSettings new file mode 100644 index 000000000..d4f48104e --- /dev/null +++ b/Folder.DotSettings @@ -0,0 +1,3 @@ + + True + \ No newline at end of file From be1f23df7f94d33d4e926589aa7ae6d2474dfbd7 Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Sun, 8 Jun 2025 01:58:33 +0200 Subject: [PATCH 59/70] clean (chat.lua): autogenerate pfUI.chat.URLFuncs based on pfUI.chat.URLPattern --- modules/chat.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/chat.lua b/modules/chat.lua index a26e24914..615a00ece 100644 --- a/modules/chat.lua +++ b/modules/chat.lua @@ -127,16 +127,16 @@ pfUI:RegisterModule("chat", "vanilla:tbc", function () ["fm"]="%s.%s.%s"}, } - pfUI.chat.URLFuncs = { - ["WWW"] = function(a1,a2,a3) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.WWW.fm,a1,a2,a3) end, - ["PROTOCOL"] = function(a1,a2) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.PROTOCOL.fm,a1,a2) end, - ["EMAIL"] = function(a1,a2,a3,a4) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.EMAIL.fm,a1,a2,a3,a4) end, - ["PORTIP"] = function(a1,a2,a3,a4,a5) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.PORTIP.fm,a1,a2,a3,a4,a5) end, - ["IP"] = function(a1,a2,a3,a4) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.IP.fm,a1,a2,a3,a4) end, - ["SHORTURL"] = function(a1,a2,a3) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.SHORTURL.fm,a1,a2,a3) end, - ["URLIP"] = function(a1,a2,a3,a4) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.URLIP.fm,a1,a2,a3,a4) end, - ["URL"] = function(a1,a2,a3) return pfUI.chat:FormatLink(pfUI.chat.URLPattern.URL.fm,a1,a2,a3) end, - } + pfUI.chat.URLFuncs = (function(urlPatternsSnapshot, pfuiChatSnapshot) + local funcs = {} + for patternName, _ in pairs(urlPatternsSnapshot) do + local patternNameSnapshot = patternName -- must snapshot + funcs[patternNameSnapshot] = function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) + return pfuiChatSnapshot:FormatLink(urlPatternsSnapshot[patternNameSnapshot].fm, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) + end + end + return funcs + end)(pfUI.chat.URLPattern, pfUI.chat) -- url copy dialog function pfUI.chat:FormatLink(formatter,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) From 8cfe277abc52b19ad0593fc1fb4e5614d3d2dab7 Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Sun, 8 Jun 2025 02:03:27 +0200 Subject: [PATCH 60/70] refa (chat.lua): make pfUI.chat:HandleLink() iterate through pfUI.chat.URLPattern instead of going through each entry it contains manually note that this inherently changes the order in which the patterns are checked to a random one because lua cannot guarantee the order of iteration in tables - in practice it shouldn't make a difference though --- modules/chat.lua | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/modules/chat.lua b/modules/chat.lua index 615a00ece..e96c1d003 100644 --- a/modules/chat.lua +++ b/modules/chat.lua @@ -166,15 +166,10 @@ pfUI:RegisterModule("chat", "vanilla:tbc", function () end function pfUI.chat:HandleLink(text) - local URLPattern = pfUI.chat.URLPattern - text = string.gsub (text, URLPattern.WWW.rx, pfUI.chat.URLFuncs.WWW) - text = string.gsub (text, URLPattern.PROTOCOL.rx, pfUI.chat.URLFuncs.PROTOCOL) - text = string.gsub (text, URLPattern.EMAIL.rx, pfUI.chat.URLFuncs.EMAIL) - text = string.gsub (text, URLPattern.PORTIP.rx, pfUI.chat.URLFuncs.PORTIP) - text = string.gsub (text, URLPattern.IP.rx, pfUI.chat.URLFuncs.IP) - text = string.gsub (text, URLPattern.SHORTURL.rx, pfUI.chat.URLFuncs.SHORTURL) - text = string.gsub (text, URLPattern.URLIP.rx, pfUI.chat.URLFuncs.URLIP) - text = string.gsub (text, URLPattern.URL.rx, pfUI.chat.URLFuncs.URL) + local urlFuncs = pfUI.chat.URLFuncs + for patternName, patternSpecs in pairs(pfUI.chat.URLPattern) do + text = string.gsub(text, patternSpecs.rx, urlFuncs[patternName]) + end return text end From 5e00b4436b76df73e576522cab883a0e5082f16e Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Wed, 18 Jun 2025 22:22:03 +0200 Subject: [PATCH 61/70] perf (unitframes.lua): optimize the way pfUI.uf:ClickAction() detects that the underlying action is a macro --- api/unitframes.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index 1472e6296..27cae8538 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -2085,7 +2085,7 @@ function pfUI.uf:ClickAction(button) showmenu = nil else -- run click cast action - local is_macro = string.find(this.clickactions[modstring], "^%/(.+)") + local is_macro = string.sub(this.clickactions[modstring], 1, 1) == "/" if superwow_active and not is_macro then CastSpellByName(this.clickactions[modstring], unitstr) From deae4ae2e93b5e77d1c95be7fe1e44f99bdd49dc Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Wed, 18 Jun 2025 22:22:28 +0200 Subject: [PATCH 62/70] perf (unitframes.lua): optimize the way pfUI.uf:EnableClickCast() detects macro-scriptlets --- api/unitframes.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index 27cae8538..95c84622c 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -2027,7 +2027,7 @@ function pfUI.uf:EnableClickCast() local prefix = modifier == "" and "" or modifier .. "-" -- check for "/" in the beginning of the string, to detect macros - if string.find(pfUI_config.unitframes["clickcast"..bconf..mconf], "^%/(.+)") then + if string.sub(pfUI_config.unitframes["clickcast"..bconf..mconf], 1, 1) == "/" then self:SetAttribute(prefix.."type"..bid, "macro") self:SetAttribute(prefix.."macrotext"..bid, pfUI_config.unitframes["clickcast"..bconf..mconf]) self:SetAttribute(prefix.."spell"..bid, nil) From 2b199a27e5a29df52fe7ccd3302226a46f710ebc Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Wed, 18 Jun 2025 22:29:16 +0200 Subject: [PATCH 63/70] perf (unitframes.lua): snapshot the desired unit_frame once per loop in pfUI.uf:EnableClickCast() for the sake of performance/readability --- api/unitframes.lua | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/api/unitframes.lua b/api/unitframes.lua index 95c84622c..c90bbbbb2 100644 --- a/api/unitframes.lua +++ b/api/unitframes.lua @@ -2020,34 +2020,35 @@ function pfUI.uf:EnableClickCast() for bid, button in pairs(buttons) do for modifier, mconf in pairs(modifiers) do local bconf = bid == 1 and "" or bid - if pfUI_config.unitframes["clickcast"..bconf..mconf] ~= "" then + local macro_text = pfUI_config.unitframes["clickcast"..bconf..mconf] + if macro_text ~= "" then -- prepare click casting if pfUI.client > 11200 then -- set attributes for tbc+ local prefix = modifier == "" and "" or modifier .. "-" -- check for "/" in the beginning of the string, to detect macros - if string.sub(pfUI_config.unitframes["clickcast"..bconf..mconf], 1, 1) == "/" then + if string.sub(macro_text, 1, 1) == "/" then self:SetAttribute(prefix.."type"..bid, "macro") - self:SetAttribute(prefix.."macrotext"..bid, pfUI_config.unitframes["clickcast"..bconf..mconf]) + self:SetAttribute(prefix.."macrotext"..bid, macro_text) self:SetAttribute(prefix.."spell"..bid, nil) - elseif string.find(pfUI_config.unitframes["clickcast"..bconf..mconf], "^target") then + elseif string.find(macro_text, "^target") then self:SetAttribute(prefix.."type"..bid, "target") self:SetAttribute(prefix.."macrotext"..bid, nil) self:SetAttribute(prefix.."spell"..bid, nil) - elseif string.find(pfUI_config.unitframes["clickcast"..bconf..mconf], "^menu") then + elseif string.find(macro_text, "^menu") then self:SetAttribute(prefix.."type"..bid, "showmenu") self:SetAttribute(prefix.."macrotext"..bid, nil) self:SetAttribute(prefix.."spell"..bid, nil) else self:SetAttribute(prefix.."type"..bid, "spell") - self:SetAttribute(prefix.."spell"..bid, pfUI_config.unitframes["clickcast"..bconf..mconf]) + self:SetAttribute(prefix.."spell"..bid, macro_text) self:SetAttribute(prefix.."macro"..bid, nil) end else -- fill clickaction table for vanillla self.clickactions = self.clickactions or {} - self.clickactions[modifier..button] = pfUI_config.unitframes["clickcast"..bconf..mconf] + self.clickactions[modifier..button] = macro_text end end end From 06303adcbe2f1f20fc4c4db0b128ba142bed788c Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Sun, 15 Feb 2026 16:13:22 +0100 Subject: [PATCH 64/70] feat (superwow.lua): introduce a wrapper around the baseline SlashCmdList.PFFOCUSCAST() defined in focus.lua and employ it when the caller specifies a hard-coded spell if scriptlet/function is passed we fallback to the original approach considering that superwow doesn't (and probably will never) support func-scriptlets --- modules/focus.lua | 2 +- modules/superwow.lua | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/focus.lua b/modules/focus.lua index a2e245827..b08c17bb7 100644 --- a/modules/focus.lua +++ b/modules/focus.lua @@ -77,7 +77,7 @@ function SlashCmdList.PFCASTFOCUS(msg) end end - local func = loadstring(msg or "") + local func = type(msg) == "function" and msg or loadstring(msg or "") if func then func() else diff --git a/modules/superwow.lua b/modules/superwow.lua index 0a68911fc..757a7a0b7 100644 --- a/modules/superwow.lua +++ b/modules/superwow.lua @@ -194,6 +194,23 @@ pfUI:RegisterModule("superwow", "vanilla", function () return guid end + -- optimize the builtin /castfocus and /pfcastfocus slash commands + local legacyfocuscast = SlashCmdList.PFFOCUSCAST + function SlashCmdList.PFCASTFOCUS(msg) + local func = type(msg) == "function" and msg or loadstring(msg or "") -- we must check this first + if func then -- if the message is a function we cant cast by guid and have to fallback to the legacy method which does support func-scriptlets + legacyfocuscast(msg) + return + end + + if not pfUI.uf.focus.label then -- the superwow approach requires just the unit-label it doesnt care about the focus.id + UIErrorsFrame:AddMessage(SPELL_FAILED_BAD_TARGETS, 1, 0, 0) + return + end + + CastSpellByName(msg, pfUI.uf.focus.label) -- superwow supports casting by unit-guid directly thus sidestepping target-swapping altogether + end + -- extend the builtin /focus slash command local legacyfocus = SlashCmdList.PFFOCUS function SlashCmdList.PFFOCUS(msg) From 480bdc93e72e79e1b6c07947231bdddeb6eedc3d Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Sun, 15 Feb 2026 20:57:32 +0100 Subject: [PATCH 65/70] clean (focus.lua): remove redundant parameter from SlashCmdList.PFSWAPFOCUS() --- modules/focus.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/focus.lua b/modules/focus.lua index b08c17bb7..08d7f477b 100644 --- a/modules/focus.lua +++ b/modules/focus.lua @@ -95,7 +95,7 @@ function SlashCmdList.PFCASTFOCUS(msg) end SLASH_PFSWAPFOCUS1, SLASH_PFSWAPFOCUS2 = '/swapfocus', '/pfswapfocus' -function SlashCmdList.PFSWAPFOCUS(msg) +function SlashCmdList.PFSWAPFOCUS() if not pfUI.uf or not pfUI.uf.focus then return end local oldunit = UnitExists("target") and strlower(UnitName("target")) From 8bcdea050a8cc185591db0d8f20abca69bd0fcf7 Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Sun, 15 Feb 2026 20:58:34 +0100 Subject: [PATCH 66/70] clean (api.lua): trivial neutral cleanups in pfUI.api.isempty() and pfUI.api.RunOOC() to resolve some static-analysis warnings about var-names --- api/api.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/api.lua b/api/api.lua index 6fc8654d6..4e57bf481 100644 --- a/api/api.lua +++ b/api/api.lua @@ -33,7 +33,7 @@ function pfUI.api.isempty(tbl) if not tbl then return true end - for k, v in pairs(tbl) do + for _ in pairs(tbl) do return false end return true @@ -88,9 +88,9 @@ function pfUI.api.RunOOC(func) if InCombatLockdown and InCombatLockdown() then return end - for key, func in pairs(queue) do - func(); - queue[key] = nil + for k, f in pairs(queue) do + f(); + queue[k] = nil end end) end From a7b565ba7332273a8305b553561cd86ae7c05057 Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Sun, 15 Feb 2026 20:59:55 +0100 Subject: [PATCH 67/70] feat (api.lua): introduce TryMemoizedFuncLoadstringForSpellCasts() which is meant to be used in order to memoize lua-func-strings passed on to various spell-casting utilities in the next few commits (/pfcast, /castfocus etc) --- api/api.lua | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/api/api.lua b/api/api.lua index 4e57bf481..30f8e0548 100644 --- a/api/api.lua +++ b/api/api.lua @@ -7,6 +7,62 @@ setfenv(1, pfUI:GetEnvironment()) gfind = string.gmatch or string.gfind mod = math.mod or mod +local loadstring_cache = {} +local loadstring_cache_size = 0 +local LOADSTRING_CACHE_MAX_SIZE = 1024 -- in practice such a max-size is more than enough we will rarely have to wipe the cache during the session +-- [ TryMemoizedFuncLoadstringForSpellCasts ] +-- Returns a function for the given string if the given msg is a string and a valid +-- lua-function can indeed be loaded from it, otherwise nil. +-- +-- If msg is an actual raw-lua-function is passed it is returned as-is without any processing. +-- This allows to use both raw functions and string-based scriptlets with the same API. +-- +-- If msg is any other type (number, boolean, ...) then nil is returned. +-- +-- The function is memoized for better performance on repeated calls with the same string. +-- +-- The cache is automatically cleared when it exceeds a certain size (1024 entries) to prevent abuse. +-- +-- In practice it is very unlikely to have more than a few dozen different scriptlets during a session, +-- so cache-nuking should be a very rare event. +function pfUI.api.TryMemoizedFuncLoadstringForSpellCasts(msg) + local msgType = type(msg) + if msgType == "function" then --10 order + return msg -- return as-is + end + + if msgType ~= "string" then --20 order + return nil -- numbers and the like are not valid for loadstring + end + + local result = loadstring_cache[msg] + if result ~= nil then -- already seen? + return result + end + + result = loadstring(msg) + if result == nil then -- invalid code + return nil + end + + if loadstring_cache_size > LOADSTRING_CACHE_MAX_SIZE then --90 just in case + loadstring_cache = {} + loadstring_cache_size = 0 + end + + loadstring_cache[msg] = result -- order + loadstring_cache_size = loadstring_cache_size + 1 -- order + + return result + + --10 special cases for when using /pfcast with funcs or scriptlets if a raw func is passed we dont need to + -- to loadstring it all + -- + --20 if the user passes a direct integer-spell-id or something else, we should not attempt to loadstring it + -- + --90 prevent abuse by capping the cache size +end + -- [ strsplit ] -- Splits a string using a delimiter. -- 'delimiter' [string] characters that will be interpreted as delimiter From cf7f3d40f3bed157bb063c68c2f2085ba743edea Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Sun, 15 Feb 2026 21:02:59 +0100 Subject: [PATCH 68/70] perf (superwow.lua): add support for superwow-aware SlashCmdList.PFCASTFOCUS() just like we did with SlashCmdList.PFFOCUS this allows us to employ unit-guid-targeting to side-step the complex target-swapping tricks we would resort to when superwow wasn't available this is a much more care-free and lightweight approach --- modules/superwow.lua | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/modules/superwow.lua b/modules/superwow.lua index 757a7a0b7..b30e14b7b 100644 --- a/modules/superwow.lua +++ b/modules/superwow.lua @@ -194,21 +194,32 @@ pfUI:RegisterModule("superwow", "vanilla", function () return guid end - -- optimize the builtin /castfocus and /pfcastfocus slash commands - local legacyfocuscast = SlashCmdList.PFFOCUSCAST + -- optimize the builtin /castfocus and /pfcastfocus slash commands when possible by using superwow + -- to cast directly to the focus-target-unit-guid thus skipping the need for complex target-swapping + local legacy_cast_focus = SlashCmdList.PFCASTFOCUS function SlashCmdList.PFCASTFOCUS(msg) - local func = type(msg) == "function" and msg or loadstring(msg or "") -- we must check this first - if func then -- if the message is a function we cant cast by guid and have to fallback to the legacy method which does support func-scriptlets - legacyfocuscast(msg) + local func = pfUI.api.TryMemoizedFuncLoadstringForSpellCasts(msg) --10 caution + if func then --10 caution + legacy_cast_focus(func) return end - if not pfUI.uf.focus.label then -- the superwow approach requires just the unit-label it doesnt care about the focus.id + if not pfUI.uf.focus.label then --50 UIErrorsFrame:AddMessage(SPELL_FAILED_BAD_TARGETS, 1, 0, 0) return end - CastSpellByName(msg, pfUI.uf.focus.label) -- superwow supports casting by unit-guid directly thus sidestepping target-swapping altogether + CastSpellByName(msg, pfUI.uf.focus.label) --90 + + --10 if the spellcast is in fact raw lua-function we cant cast by guid we have to fallback + -- to the legacy method which does support func-scriptlets + -- + --50 the superwow-approach requires just the unit-guid-label it doesnt care about the focus.id + -- which is typically dud anyway + -- + --90 by using superwow to cast directly to a unit-guid we completely sidestep the complex mechanics + -- of target-swapping altogether which is the entire point here for vastly improved ui-performance + -- when spamming spells end -- extend the builtin /focus slash command From 0daa34491d34d9b824104e0c8c9e656fbeefb913 Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Sun, 15 Feb 2026 21:09:00 +0100 Subject: [PATCH 69/70] perf (focus.lua, mouseover.lua, superwow.lua): replace loadstring() calls in _G.SlashCmdList.PFCAST() and SlashCmdList.PFCASTFOCUS() with pfUI.api.TryMemoizedFuncLoadstringForSpellCasts() to enjoy better runtime performance when the user passes a lua-func-string as an added bonus this commit also adds seamless support for passing actual raw functions to SlashCmdList.PFCASTFOCUS() ala: SlashCmdList.PFCASTFOCUS(function() CastspellByName("Renew", 1); end) which is extremely useful for advanced pure-lua macros. Old was: Before this commit we would have to write this kind of stuff as a string SlashCmdList.PFCASTFOCUS( 'function() CastspellByName("Renew", 1); end' ) this was both 10x slower and was extremely cumbersome and error-prone for the user if he wanted to pass some variable-state inside the string-func-callback. --- modules/focus.lua | 2 +- modules/mouseover.lua | 2 +- modules/superwow.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/focus.lua b/modules/focus.lua index 08d7f477b..2857f4cbc 100644 --- a/modules/focus.lua +++ b/modules/focus.lua @@ -77,7 +77,7 @@ function SlashCmdList.PFCASTFOCUS(msg) end end - local func = type(msg) == "function" and msg or loadstring(msg or "") + local func = pfUI.api.TryMemoizedFuncLoadstringForSpellCasts(msg) if func then func() else diff --git a/modules/mouseover.lua b/modules/mouseover.lua index 918a39768..2a0226037 100644 --- a/modules/mouseover.lua +++ b/modules/mouseover.lua @@ -34,7 +34,7 @@ pfUI:RegisterModule("mouseover", "vanilla", function () _G.SLASH_PFCAST1, _G.SLASH_PFCAST2 = "/pfcast", "/pfmouse" function SlashCmdList.PFCAST(msg) local restore_target = true - local func = loadstring(msg or "") + local func = pfUI.api.TryMemoizedFuncLoadstringForSpellCasts(msg or "") local unit = "mouseover" if not UnitExists(unit) then diff --git a/modules/superwow.lua b/modules/superwow.lua index b30e14b7b..fedbad12c 100644 --- a/modules/superwow.lua +++ b/modules/superwow.lua @@ -49,7 +49,7 @@ pfUI:RegisterModule("superwow", "vanilla", function () -- Add native mouseover support if SUPERWOW_VERSION and pfUI.uf and pfUI.uf.mouseover then _G.SlashCmdList.PFCAST = function(msg) - local func = loadstring(msg or "") + local func = pfUI.api.TryMemoizedFuncLoadstringForSpellCasts(msg or "") local unit = "mouseover" if not UnitExists(unit) then From 68afb4ed59642ce91af084bc5bc376da6d894569 Mon Sep 17 00:00:00 2001 From: Dominick Sidiropoulos Date: Sun, 15 Feb 2026 21:09:21 +0100 Subject: [PATCH 70/70] clean (superwow.lua): resolve some trivial static-analysis warnings about unused variables --- modules/superwow.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/superwow.lua b/modules/superwow.lua index fedbad12c..8dd739603 100644 --- a/modules/superwow.lua +++ b/modules/superwow.lua @@ -36,7 +36,7 @@ pfUI:RegisterModule("superwow", "vanilla", function () QueueFunction(function() local pfCombatText_AddMessage = _G.CombatText_AddMessage _G.CombatText_AddMessage = function(message, a, b, c, d, e, f) - local match, _, hex = string.find(message, ".+ %[(0x.+)%]") + local _, _, hex = string.find(message, ".+ %[(0x.+)%]") if hex and UnitName(hex) then message = string.gsub(message, hex, UnitName(hex)) end @@ -90,7 +90,7 @@ pfUI:RegisterModule("superwow", "vanilla", function () local config = pfUI.uf.player.config local mana = config.defcolor == "0" and config.manacolor or pfUI_config.unitframes.manacolor local r, g, b, a = pfUI.api.strsplit(",", mana) - local rawborder, default_border = GetBorderSize("unitframes") + local _, default_border = GetBorderSize("unitframes") local _, class = UnitClass("player") local width = config.pwidth ~= "-1" and config.pwidth or config.width