dpslog: DPSMate CLEU adapter with per-combat A/B profiling
Adds DPSMate_CLEUAdapter.lua -- replaces DPSMate's string-parsing CHAT_MSG_* system with structured COMBAT_LOG_EVENT data from our DLL. Adapter maps CLEU subevents directly to DPSMate.DB API calls: DamageDone, DamageTaken, EnemyDamage, Healing, HealingTaken, DeathHistory, Kick, Dispels, BuildBuffs, CCBreaker, etc. Eliminates all strfind pattern matching from the combat log path. Toggle: /dpscleu (on/off/status) Benchmark: /dpsbench -- always-on per-combat A/B profiling. Resets at combat start, reports at combat end, flips mode for next combat. Reports events, total ms, us/event, GC delta, and percentage comparison between CLEU and original modes. Starts in CLEU mode by default.
This commit is contained in:
@@ -0,0 +1,970 @@
|
||||
-- Global Variables
|
||||
DPSMate = {}
|
||||
DPSMate.VERSION = 130
|
||||
DPSMate.LOCALE = GetLocale()
|
||||
DPSMate.SYNCVERSION = DPSMate.VERSION..DPSMate.LOCALE
|
||||
DPSMate.Parser = CreateFrame("Frame", nil, UIParent)
|
||||
DPSMate.L = {}
|
||||
DPSMate.DB = CreateFrame("Frame", nil, UIParent)
|
||||
DPSMate.Options = CreateFrame("Frame", nil, UIParent)
|
||||
DPSMate.Sync = CreateFrame("Frame", nil, UIParent)
|
||||
DPSMate.Modules = {}
|
||||
DPSMate.Events = {
|
||||
--"CHAT_MSG_ADDON",
|
||||
"PLAYER_AURAS_CHANGED",
|
||||
|
||||
-- Damage
|
||||
"CHAT_MSG_COMBAT_SELF_HITS",
|
||||
"CHAT_MSG_COMBAT_SELF_MISSES",
|
||||
"CHAT_MSG_SPELL_SELF_DAMAGE",
|
||||
"CHAT_MSG_COMBAT_PARTY_HITS",
|
||||
"CHAT_MSG_SPELL_PARTY_DAMAGE",
|
||||
"CHAT_MSG_COMBAT_PARTY_MISSES",
|
||||
"CHAT_MSG_COMBAT_FRIENDLYPLAYER_HITS",
|
||||
"CHAT_MSG_COMBAT_FRIENDLYPLAYER_MISSES",
|
||||
"CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE",
|
||||
-- Pet Damage
|
||||
"CHAT_MSG_COMBAT_PET_HITS",
|
||||
"CHAT_MSG_COMBAT_PET_MISSES",
|
||||
--"CHAT_MSG_SPELL_PET_BUFF",
|
||||
"CHAT_MSG_SPELL_PET_DAMAGE",
|
||||
|
||||
-- EDD (Enemy player) / DeathHistory
|
||||
"CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS",
|
||||
"CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES",
|
||||
"CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE",
|
||||
"CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE",
|
||||
|
||||
-- Damage taken (Also EDD) / DeathHistory
|
||||
"CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS",
|
||||
"CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES",
|
||||
"CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE",
|
||||
"CHAT_MSG_COMBAT_CREATURE_VS_PARTY_HITS",
|
||||
"CHAT_MSG_COMBAT_CREATURE_VS_PARTY_MISSES",
|
||||
"CHAT_MSG_SPELL_CREATURE_VS_PARTY_DAMAGE",
|
||||
"CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_HITS",
|
||||
"CHAT_MSG_COMBAT_CREATURE_VS_CREATURE_MISSES",
|
||||
"CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE",
|
||||
"CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE",
|
||||
"CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE",
|
||||
"CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE",
|
||||
"CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE",
|
||||
|
||||
-- Healing/Absorbs/Fail/DeathHistory/Dispels
|
||||
"CHAT_MSG_SPELL_SELF_BUFF",
|
||||
"CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS",
|
||||
"CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF",
|
||||
"CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS",
|
||||
"CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF",
|
||||
"CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS",
|
||||
"CHAT_MSG_SPELL_PARTY_BUFF",
|
||||
"CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS",
|
||||
|
||||
-- Absorbs/Auras
|
||||
"CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF",
|
||||
"CHAT_MSG_SPELL_DAMAGESHIELDS_ON_OTHERS",
|
||||
"CHAT_MSG_SPELL_BREAK_AURA",
|
||||
"CHAT_MSG_SPELL_AURA_GONE_SELF",
|
||||
"CHAT_MSG_SPELL_AURA_GONE_OTHER",
|
||||
"CHAT_MSG_SPELL_AURA_GONE_PARTY",
|
||||
|
||||
-- Death/DeathHistory
|
||||
"CHAT_MSG_COMBAT_FRIENDLY_DEATH",
|
||||
"CHAT_MSG_COMBAT_HOSTILE_DEATH",
|
||||
}
|
||||
DPSMate.Registered = true
|
||||
DPSMate.RegistredModules = {}
|
||||
DPSMate.ModuleNames = {}
|
||||
DPSMate.UserId = nil
|
||||
DPSMate.AbilityId = nil
|
||||
DPSMate.Key = 1
|
||||
DPSMate.DelayMsg = {}
|
||||
DPSMate.BabbleSpell = BabbleSpell
|
||||
DPSMate.BabbleBoss = BabbleBoss
|
||||
|
||||
-- Knife was wrong - 11.06.2018
|
||||
|
||||
-- Local Variables
|
||||
local _G = getglobal
|
||||
local classcolor = {
|
||||
rogue = {r=1.0, g=0.96, b=0.41},
|
||||
priest = {r=1,g=1,b=1},
|
||||
druid = {r=1,g=0.49,b=0.04},
|
||||
warrior = {r=0.78,g=0.61,b=0.43},
|
||||
warlock = {r=0.58,g=0.51,b=0.79},
|
||||
mage = {r=0.41,g=0.8,b=0.94},
|
||||
hunter = {r=0.67,g=0.83,b=0.45},
|
||||
paladin = {r=0.96,g=0.55,b=0.73},
|
||||
shaman = {r=0,g=0.44,b=0.87},
|
||||
}
|
||||
local t = {}
|
||||
local tinsert = table.insert
|
||||
local strgsub = string.gsub
|
||||
local func = function(c) tinsert(t, c) end
|
||||
local strformat = string.format
|
||||
local strgfind = string.gfind
|
||||
local pairs = pairs
|
||||
local strlen = strlen
|
||||
local strsub = strsub
|
||||
local tonumber = tonumber
|
||||
local getn = getn
|
||||
local tconcat = table.concat
|
||||
local SendChatMessage = function(prio, prefix, text, chattype, language, destination)
|
||||
ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, language, destination)
|
||||
end
|
||||
|
||||
local DPSSettings = {}
|
||||
local DPSHist = {}
|
||||
local fontRefreshAt = nil
|
||||
local savedFontSettings = nil
|
||||
local GT = GetTime
|
||||
|
||||
-- Begin functions
|
||||
|
||||
function DPSMate:OnLoad()
|
||||
SLASH_DPSMate1 = "/dps"
|
||||
SlashCmdList["DPSMate"] = function(msg) DPSMate:SlashCMDHandler(msg) end
|
||||
|
||||
DPSMate:UpdatePointer()
|
||||
|
||||
-- Snapshot font settings before skinning addons can overwrite them
|
||||
savedFontSettings = {}
|
||||
for k, w in pairs(DPSSettings["windows"]) do
|
||||
savedFontSettings[k] = {
|
||||
barfont = w["barfont"],
|
||||
barfontsize = w["barfontsize"],
|
||||
barfontflag = w["barfontflag"],
|
||||
titlebarfont = w["titlebarfont"],
|
||||
titlebarfontsize = w["titlebarfontsize"],
|
||||
titlebarfontflag = w["titlebarfontflag"],
|
||||
}
|
||||
end
|
||||
|
||||
DPSMate:InitializeFrames()
|
||||
DPSMate.Options:InitializeConfigMenu()
|
||||
|
||||
if DPSMate.L.UpdateFrameTexts then
|
||||
DPSMate.L.UpdateFrameTexts()
|
||||
end
|
||||
|
||||
-- Schedule a deferred font refresh so that font settings survive
|
||||
-- skinning addons (e.g. pfUI) that override fonts after load.
|
||||
fontRefreshAt = GT() + 1
|
||||
end
|
||||
|
||||
function DPSMate:UpdatePointer()
|
||||
DPSSettings = DPSMateSettings
|
||||
DPSHist = DPSMateHistory
|
||||
end
|
||||
|
||||
function DPSMate:SlashCMDHandler(msg)
|
||||
if (msg) then
|
||||
local cmd = msg
|
||||
if cmd == "lock" then
|
||||
DPSMate.Options:Lock()
|
||||
elseif cmd == "unlock" then
|
||||
DPSMate.Options:Unlock()
|
||||
elseif cmd == "config" then
|
||||
DPSMate_ConfigMenu:Show()
|
||||
elseif cmd == "reset" then
|
||||
DPSMate:SendMessage(DPSMate.L["resetconfirm"])
|
||||
elseif cmd == "resetconfirm" then
|
||||
DPSMateUser = {}
|
||||
DPSMateAbility = {}
|
||||
DPSMate.DB.abilitylen = 1
|
||||
DPSMate.DB.userlen = 1
|
||||
DPSMate.UserId = {}
|
||||
DPSMate.Options:PopUpAccept(true, true)
|
||||
DPSMate:SendMessage(DPSMate.L["resetdone"])
|
||||
elseif cmd == "showAll" then
|
||||
for _, val in DPSSettings["windows"] do DPSMate.Options:Show(getglobal("DPSMate_"..val["name"])) end
|
||||
elseif cmd == "hideAll" then
|
||||
for _, val in DPSSettings["windows"] do DPSMate.Options:Hide(getglobal("DPSMate_"..val["name"])) end
|
||||
elseif strsub(cmd, 1, 4) == "show" then
|
||||
local frame = _G("DPSMate_"..strsub(cmd, 6))
|
||||
if frame then
|
||||
DPSMate.Options:Show(frame)
|
||||
else
|
||||
DPSMate:SendMessage(DPSMate.L["framesavailable"])
|
||||
for _, val in pairs(DPSSettings["windows"]) do
|
||||
DPSMate:SendMessage("|c3ffddd80- "..val["name"].."|r")
|
||||
end
|
||||
end
|
||||
elseif strsub(cmd, 1, 4) == "hide" then
|
||||
local frame = _G("DPSMate_"..strsub(cmd, 6))
|
||||
if frame then
|
||||
DPSMate.Options:Hide(frame)
|
||||
else
|
||||
DPSMate:SendMessage(DPSMate.L["framesavailable"])
|
||||
for _, val in pairs(DPSSettings["windows"]) do
|
||||
DPSMate:SendMessage("|c3ffddd80- "..val["name"].."|r")
|
||||
end
|
||||
end
|
||||
else
|
||||
DPSMate:SendMessage(DPSMate.L["slashabout"])
|
||||
DPSMate:SendMessage(DPSMate.L["slashusage"])
|
||||
DPSMate:SendMessage(DPSMate.L["slashlock"])
|
||||
DPSMate:SendMessage(DPSMate.L["slashunlock"])
|
||||
DPSMate:SendMessage(DPSMate.L["slashshowAll"])
|
||||
DPSMate:SendMessage(DPSMate.L["slashhideAll"])
|
||||
DPSMate:SendMessage(DPSMate.L["slashshow"])
|
||||
DPSMate:SendMessage(DPSMate.L["slashhide"])
|
||||
DPSMate:SendMessage(DPSMate.L["slashconfig"])
|
||||
DPSMate:SendMessage(DPSMate.L["slashreset"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DPSMate:InitializeFrames()
|
||||
if not DPSSettings["windows"][1] then return end
|
||||
for k, val in pairs(DPSSettings["windows"]) do
|
||||
if not _G("DPSMate_"..val["name"]) then
|
||||
local f=CreateFrame("Frame", "DPSMate_"..val["name"], UIParent, "DPSMate_Statusframe")
|
||||
f.Key=k
|
||||
end
|
||||
local frame = _G("DPSMate_"..val["name"])
|
||||
frame.fborder = _G("DPSMate_"..val["name"].."_Border")
|
||||
frame:SetToplevel(true)
|
||||
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total_Name"):SetText(self.L["total"])
|
||||
|
||||
if (val["position"] and val["position"][1]) then
|
||||
frame:ClearAllPoints()
|
||||
frame:SetPoint(val["position"][1], UIParent, val["position"][1], val["position"][2], val["position"][3])
|
||||
end
|
||||
if (val["savsize"] and val["savsize"][1]) then
|
||||
frame:SetWidth(val["savsize"][1])
|
||||
frame:SetHeight(val["savsize"][2])
|
||||
end
|
||||
|
||||
DPSMate.Options:ToggleDrewDrop(1, DPSMate.DB:GetOptionsTrue(1, k), frame)
|
||||
DPSMate.Options:ToggleDrewDrop(2, DPSMate.DB:GetOptionsTrue(2, k), frame)
|
||||
|
||||
frame.fborder:SetAlpha(val["borderopacity"] or 0)
|
||||
frame.fborder:SetFrameStrata(DPSMate.Options.stratas[val["borderstrata"] or 1])
|
||||
frame.fborder:SetBackdrop({
|
||||
bgFile = "",
|
||||
edgeFile = DPSMate.Options.bordertextures[val["bordertexture"] or "UI-Tooltip-Border"], tile = true, tileSize = 12, edgeSize = 10,
|
||||
insets = { left = 5, right = 5, top = 3, bottom = 1 }
|
||||
})
|
||||
frame.fborder:SetBackdropBorderColor(val["contentbordercolor"][1], val["contentbordercolor"][2], val["contentbordercolor"][3])
|
||||
|
||||
local head = _G("DPSMate_"..val["name"].."_Head")
|
||||
head.font = _G("DPSMate_"..val["name"].."_Head_Font")
|
||||
head.bg = _G("DPSMate_"..val["name"].."_Head_Background")
|
||||
head.sync = _G("DPSMate_"..val["name"].."_Head_Sync")
|
||||
|
||||
if DPSSettings["sync"] then
|
||||
head.sync:GetNormalTexture():SetVertexColor(0.67,0.83,0.45,1)
|
||||
else
|
||||
head.sync:GetNormalTexture():SetVertexColor(1,0,0,1)
|
||||
end
|
||||
|
||||
if DPSSettings["lock"] then
|
||||
_G("DPSMate_"..val["name"].."_Resize"):Hide()
|
||||
end
|
||||
if not val["titlebar"] then
|
||||
head:Hide()
|
||||
end
|
||||
frame:SetAlpha(val["opacity"])
|
||||
head.font:SetTextColor(val["titlebarfontcolor"][1],val["titlebarfontcolor"][2],val["titlebarfontcolor"][3])
|
||||
head.bg:SetTexture(DPSMate.Options.statusbars[val["titlebartexture"]])
|
||||
head.bg:SetVertexColor(val["titlebarbgcolor"][1], val["titlebarbgcolor"][2], val["titlebarbgcolor"][3])
|
||||
head.bg:SetAlpha(val["titlebaropacity"] or 1)
|
||||
head.font:SetFont(DPSMate.Options.fonts[val["titlebarfont"]], val["titlebarfontsize"], DPSMate.Options.fontflags[val["titlebarfontflag"]])
|
||||
head:SetHeight(val["titlebarheight"])
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Background"):SetTexture(DPSMate.Options.bgtexture[val["contentbgtexture"]])
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Background"):SetVertexColor(val["contentbgcolor"][1], val["contentbgcolor"][2], val["contentbgcolor"][3])
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Background"):SetAlpha(val["bgopacity"] or 1)
|
||||
frame:SetScale(val["scale"])
|
||||
_G("DPSMate_"..val["name"].."_Head_Enable"):SetChecked(DPSSettings["enable"])
|
||||
|
||||
-- Styles // Bars
|
||||
local child = _G("DPSMate_"..val["name"].."_ScrollFrame_Child")
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total"):SetPoint("TOPLEFT", child, "TOPLEFT")
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total"):SetPoint("TOPRIGHT", child, "TOPRIGHT")
|
||||
if DPSSettings["showtotals"] then
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total"):SetHeight(val["barheight"])
|
||||
else
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total"):SetHeight(0.00001)
|
||||
end
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total"):SetStatusBarTexture(DPSMate.Options.statusbars[val["bartexture"]])
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total"):SetStatusBarColor(1,1,1,val["totopacity"] or 1)
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total_BG"):SetTexture(DPSMate.Options.statusbars[val["bartexture"]])
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total_BG"):SetAlpha(val["totopacity"] or 1)
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total_Name"):SetFont(DPSMate.Options.fonts[val["barfont"]], val["barfontsize"], DPSMate.Options.fontflags[val["barfontflag"]])
|
||||
_G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total_Value"):SetFont(DPSMate.Options.fonts[val["barfont"]], val["barfontsize"], DPSMate.Options.fontflags[val["barfontflag"]])
|
||||
for i=1, 40 do
|
||||
local bar = _G("DPSMate_"..val["name"].."_ScrollFrame_Child_StatusBar"..i)
|
||||
bar.name = _G("DPSMate_"..val["name"].."_ScrollFrame_Child_StatusBar"..i.."_Name")
|
||||
bar.value = _G("DPSMate_"..val["name"].."_ScrollFrame_Child_StatusBar"..i.."_Value")
|
||||
bar.icon = _G("DPSMate_"..val["name"].."_ScrollFrame_Child_StatusBar"..i.."_Icon")
|
||||
bar.bg = _G("DPSMate_"..val["name"].."_ScrollFrame_Child_StatusBar"..i.."_BG")
|
||||
|
||||
-- Postition
|
||||
bar:SetPoint("TOPLEFT", child, "TOPLEFT")
|
||||
bar:SetPoint("TOPRIGHT", child, "TOPRIGHT")
|
||||
if i>1 then
|
||||
bar:SetPoint("TOPLEFT", _G("DPSMate_"..val["name"].."_ScrollFrame_Child_StatusBar"..(i-1)), "BOTTOMLEFT", 0, -1*val["barspacing"])
|
||||
else
|
||||
if DPSSettings["showtotals"] then
|
||||
bar:SetPoint("TOPLEFT", _G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total"), "BOTTOMLEFT", 0, -1*val["barspacing"])
|
||||
else
|
||||
bar:SetPoint("TOPLEFT", _G("DPSMate_"..val["name"].."_ScrollFrame_Child_Total"), "BOTTOMLEFT", 0, -1)
|
||||
end
|
||||
end
|
||||
if val["classicons"] then
|
||||
bar.name:ClearAllPoints()
|
||||
bar.name:SetPoint("TOPLEFT", bar, "TOPLEFT", val["barheight"], 0)
|
||||
bar.name:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT")
|
||||
bar.icon:SetWidth(val["barheight"])
|
||||
bar.icon:SetHeight(val["barheight"])
|
||||
bar.icon:Show()
|
||||
end
|
||||
|
||||
-- Styles
|
||||
bar.name:SetFont(DPSMate.Options.fonts[val["barfont"]], val["barfontsize"], DPSMate.Options.fontflags[val["barfontflag"]])
|
||||
bar.name:SetTextColor(val["barfontcolor"][1],val["barfontcolor"][2],val["barfontcolor"][3])
|
||||
bar.value:SetFont(DPSMate.Options.fonts[val["barfont"]], val["barfontsize"], DPSMate.Options.fontflags[val["barfontflag"]])
|
||||
bar.value:SetTextColor(val["barfontcolor"][1],val["barfontcolor"][2],val["barfontcolor"][3])
|
||||
bar:SetStatusBarTexture(DPSMate.Options.statusbars[val["bartexture"]])
|
||||
bar.bg:SetTexture(DPSMate.Options.statusbars[val["bartexture"]])
|
||||
bar:SetHeight(val["barheight"])
|
||||
if val["barbg"] then
|
||||
bar.bg:SetVertexColor(val["bgbarcolor"][1],val["bgbarcolor"][2],val["bgbarcolor"][3], 0)
|
||||
else
|
||||
bar.bg:SetVertexColor(val["bgbarcolor"][1],val["bgbarcolor"][2],val["bgbarcolor"][3], 0.5)
|
||||
end
|
||||
|
||||
end
|
||||
DPSMate.Options:SelectRealtime(frame, val["realtime"])
|
||||
|
||||
if (val["hidden"] == true) then
|
||||
frame:Hide()
|
||||
end
|
||||
end
|
||||
DPSMate.Options:ToggleTitleBarButtonState()
|
||||
DPSMate.Options:HideWhenSolo()
|
||||
if not DPSSettings["enable"] then
|
||||
self:Disable()
|
||||
else
|
||||
self:Enable()
|
||||
end
|
||||
|
||||
|
||||
-- Report delay button
|
||||
DPSMate_Report_Delay:SetChecked(DPSSettings["reportdelay"])
|
||||
|
||||
DPSMate_MiniMap:SetToplevel(true)
|
||||
DPSMate_PopUp:SetToplevel(true)
|
||||
DPSMate_Vote:SetToplevel(true)
|
||||
DPSMate_Logout:SetToplevel(true)
|
||||
DPSMate_Report:SetToplevel(true)
|
||||
DPSMate_ConfigMenu:SetToplevel(true)
|
||||
end
|
||||
|
||||
function DPSMate:ProbZero(val)
|
||||
if (val==0) then
|
||||
return 1;
|
||||
end
|
||||
return val;
|
||||
end
|
||||
|
||||
function DPSMate:TMax(t)
|
||||
local max = 0
|
||||
for _,val in pairs(t) do
|
||||
if val>max then
|
||||
max=val
|
||||
end
|
||||
end
|
||||
return max
|
||||
end
|
||||
|
||||
function DPSMate:TableLength(t)
|
||||
local count = 0
|
||||
if (t) then
|
||||
count = getn(t)
|
||||
if count<=1 then
|
||||
count = 0
|
||||
for _,_ in pairs(t) do
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
return count
|
||||
end
|
||||
|
||||
function DPSMate:TContains(t, value)
|
||||
if (t) then
|
||||
for cat, val in pairs(t) do
|
||||
if val == value or cat==value then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function DPSMate:GetKeyByVal(t, value)
|
||||
for cat, val in pairs(t) do
|
||||
if val == value then
|
||||
return cat
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DPSMate:GetKeyByValInTT(t, x, y)
|
||||
for cat, val in pairs(t) do
|
||||
if (type(val) == "table") then
|
||||
if (x==val[y]) then
|
||||
return cat
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DPSMate:InvertTable(t)
|
||||
local s={}
|
||||
for cat, val in pairs(t) do
|
||||
s[val]=cat
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
function DPSMate:CopyTable(t)
|
||||
local s={}
|
||||
for cat, val in pairs(t) do
|
||||
if type(val) == "table" then
|
||||
s[cat] = self:CopyTable(val)
|
||||
else
|
||||
s[cat] = val
|
||||
end
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
function DPSMate:CopyTableStripInstant(t, depth)
|
||||
local s={}
|
||||
depth = depth or 0
|
||||
for cat, val in pairs(t) do
|
||||
if depth >= 2 and cat == "i" then
|
||||
-- Skip ["i"] instant-damage dictionaries at ability level
|
||||
elseif type(val) == "table" then
|
||||
s[cat] = self:CopyTableStripInstant(val, depth + 1)
|
||||
else
|
||||
s[cat] = val
|
||||
end
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
function DPSMate:PruneStaleUsers()
|
||||
-- Collect all user IDs referenced in active metric data and history
|
||||
local activeIds = {}
|
||||
local metrics = {DPSMateDamageDone, DPSMateDamageTaken, DPSMateEDD, DPSMateEDT, DPSMateTHealing, DPSMateEHealing, DPSMateOverhealing, DPSMateHealingTaken, DPSMateEHealingTaken, DPSMateOverhealingTaken, DPSMateAbsorbs, DPSMateDispels, DPSMateDeaths, DPSMateInterrupts, DPSMateAurasGained, DPSMateThreat, DPSMateFails, DPSMateCCBreaker}
|
||||
-- Check active data (mode [1] and [2])
|
||||
for _, metric in pairs(metrics) do
|
||||
if metric then
|
||||
for mode = 1, 2 do
|
||||
if metric[mode] then
|
||||
for uid, _ in pairs(metric[mode]) do
|
||||
activeIds[uid] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Check history segments
|
||||
for cat, segments in pairs(DPSMateHistory) do
|
||||
if cat ~= "names" and type(segments) == "table" then
|
||||
for _, segment in pairs(segments) do
|
||||
if type(segment) == "table" then
|
||||
for uid, _ in pairs(segment) do
|
||||
activeIds[uid] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Remove users whose IDs aren't referenced anywhere
|
||||
local removed = 0
|
||||
for name, data in pairs(DPSMateUser) do
|
||||
if data[1] and not activeIds[data[1]] then
|
||||
DPSMateUser[name] = nil
|
||||
removed = removed + 1
|
||||
end
|
||||
end
|
||||
if removed > 0 then
|
||||
self.UserId = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Strip ["i"] sub-tables from all modes of all metrics that use them.
|
||||
-- Covers damage/healing/threat (per-second time buckets) as well as dispels,
|
||||
-- interrupts, and absorbs (event log arrays stored under ["i"]).
|
||||
-- Called on login and on logout to keep SavedVariables compact.
|
||||
--
|
||||
-- A recursive walk is used: wherever ["i"] is a table it is cleared to {}.
|
||||
-- Numbers stored under ["i"] are left untouched.
|
||||
-- Using {} rather than nil keeps combat event writers safe.
|
||||
local function stripInstantRecursive(t)
|
||||
for k, v in pairs(t) do
|
||||
if k == "i" and type(v) == "table" then
|
||||
t[k] = {}
|
||||
elseif k ~= "i" and type(v) == "table" then
|
||||
stripInstantRecursive(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DPSMate:StripInstantFromMode1()
|
||||
local metrics = {DPSMateDamageDone, DPSMateDamageTaken, DPSMateEDD, DPSMateEDT,
|
||||
DPSMateTHealing, DPSMateEHealing, DPSMateOverhealing, DPSMateHealingTaken,
|
||||
DPSMateEHealingTaken, DPSMateOverhealingTaken, DPSMateThreat,
|
||||
DPSMateDispels, DPSMateInterrupts, DPSMateAbsorbs}
|
||||
for _, metric in pairs(metrics) do
|
||||
if metric then
|
||||
if metric[1] then stripInstantRecursive(metric[1]) end
|
||||
if metric[2] then stripInstantRecursive(metric[2]) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Collapse AurasGained timestamp arrays in Mode [1] and [2] into compact uptime totals.
|
||||
-- path[1] (gain times) and path[2] (loss times) grow unboundedly with each buff
|
||||
-- application. The pre-computed total is stored in path[7] so EvalTable can still
|
||||
-- display accurate uptime percentages across sessions.
|
||||
function DPSMate:CollapseAuraTimestamps()
|
||||
if not DPSMateAurasGained then return end
|
||||
for mode = 1, 2 do
|
||||
local modeData = DPSMateAurasGained[mode]
|
||||
if modeData then
|
||||
for uid, abilities in pairs(modeData) do
|
||||
for abilityId, path in pairs(abilities) do
|
||||
if type(path) == "table" and type(path[1]) == "table" then
|
||||
local total = path[7] or 0
|
||||
for i, gainTime in pairs(path[1]) do
|
||||
if path[2] and path[2][i] then
|
||||
total = total + (path[2][i] - gainTime)
|
||||
end
|
||||
end
|
||||
path[7] = total
|
||||
path[1] = {}
|
||||
path[2] = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function DPSMate:GetUserById(id)
|
||||
if not self.UserId or not self.UserId[id] then
|
||||
self.UserId = {}
|
||||
for cat, val in DPSMateUser do
|
||||
self.UserId[val[1]] = cat
|
||||
end
|
||||
end
|
||||
return self.UserId[id]
|
||||
end
|
||||
|
||||
function DPSMate:GetPetsByOwner(arr)
|
||||
local lookup = {}
|
||||
for cat, _ in pairs(arr) do
|
||||
local name = self:GetUserById(cat)
|
||||
if name and DPSMateUser[name] and DPSMateUser[name][4] and DPSMateUser[name][6] then
|
||||
local oid = DPSMateUser[name][6]
|
||||
if not lookup[oid] then
|
||||
lookup[oid] = {}
|
||||
end
|
||||
table.insert(lookup[oid], cat)
|
||||
end
|
||||
end
|
||||
return lookup
|
||||
end
|
||||
|
||||
function DPSMate:GetAbilityById(id)
|
||||
if not self.AbilityId or not self.AbilityId[id] then
|
||||
self.AbilityId = {}
|
||||
for cat, val in DPSMateAbility do
|
||||
self.AbilityId[val[1]] = cat
|
||||
end
|
||||
end
|
||||
return self.AbilityId[id]
|
||||
end
|
||||
|
||||
function DPSMate:GetMaxValue(arr, key)
|
||||
local max = 0
|
||||
for _, val in arr do
|
||||
if val[key]>max then
|
||||
max=val[key]
|
||||
end
|
||||
end
|
||||
return max
|
||||
end
|
||||
|
||||
function DPSMate:GetMinValue(arr, key)
|
||||
local min
|
||||
for _, val in arr do
|
||||
if not min or val[key]<min then
|
||||
min = val[key]
|
||||
end
|
||||
end
|
||||
return min or 0
|
||||
end
|
||||
|
||||
function DPSMate:ScaleDown(arr, start)
|
||||
local t = {}
|
||||
for cat, val in arr do
|
||||
t[cat] = {(val[1]-start+1), val[2]}
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
function DPSMate:RefreshFonts()
|
||||
if not DPSSettings["windows"][1] then return end
|
||||
if not savedFontSettings then return end
|
||||
local fonts = self.Options.fonts
|
||||
local flags = self.Options.fontflags
|
||||
for k, c in pairs(DPSSettings["windows"]) do
|
||||
local saved = savedFontSettings[k]
|
||||
if saved then
|
||||
-- Restore user's saved font settings into the live table
|
||||
c["barfont"] = saved.barfont
|
||||
c["barfontsize"] = saved.barfontsize
|
||||
c["barfontflag"] = saved.barfontflag
|
||||
c["titlebarfont"] = saved.titlebarfont
|
||||
c["titlebarfontsize"] = saved.titlebarfontsize
|
||||
c["titlebarfontflag"] = saved.titlebarfontflag
|
||||
end
|
||||
local barFont = fonts[c["barfont"]]
|
||||
local barSize = c["barfontsize"]
|
||||
local barFlag = flags[c["barfontflag"]]
|
||||
local titleFont = fonts[c["titlebarfont"]]
|
||||
local titleSize = c["titlebarfontsize"]
|
||||
local titleFlag = flags[c["titlebarfontflag"]]
|
||||
local name = c["name"]
|
||||
_G("DPSMate_"..name.."_Head_Font"):SetFont(titleFont, titleSize, titleFlag)
|
||||
_G("DPSMate_"..name.."_ScrollFrame_Child_Total_Name"):SetFont(barFont, barSize, barFlag)
|
||||
_G("DPSMate_"..name.."_ScrollFrame_Child_Total_Value"):SetFont(barFont, barSize, barFlag)
|
||||
for i=1, 40 do
|
||||
_G("DPSMate_"..name.."_ScrollFrame_Child_StatusBar"..i.."_Name"):SetFont(barFont, barSize, barFlag)
|
||||
_G("DPSMate_"..name.."_ScrollFrame_Child_StatusBar"..i.."_Value"):SetFont(barFont, barSize, barFlag)
|
||||
end
|
||||
end
|
||||
savedFontSettings = nil
|
||||
end
|
||||
|
||||
local framePointerCache = {}
|
||||
function DPSMate:InvalidateFrameCache()
|
||||
framePointerCache = {}
|
||||
end
|
||||
function DPSMate:SetStatusBarValue()
|
||||
|
||||
if not DPSSettings["windows"][1] or self.Options.TestMode then return end
|
||||
|
||||
-- Deferred font refresh: wait ~1s after load for skinning addons to finish,
|
||||
-- then re-apply saved font settings once.
|
||||
if fontRefreshAt and GT() >= fontRefreshAt then
|
||||
fontRefreshAt = nil
|
||||
self:RefreshFonts()
|
||||
end
|
||||
local arr, cbt, ecbt, user, val, perc, strt, statusbar, r, g, b, img, len
|
||||
for k,c in pairs(DPSSettings.windows) do
|
||||
arr, cbt, ecbt = self:GetMode(k)
|
||||
user, val, perc, strt = self:GetSettingValues(arr,cbt,k,ecbt)
|
||||
|
||||
-- Caching the global lookups
|
||||
if not framePointerCache[k] then
|
||||
framePointerCache[k] = {}
|
||||
framePointerCache[k][1] = _G("DPSMate_"..c["name"].."_ScrollFrame_Child_Total_Value")
|
||||
framePointerCache[k][2] = _G("DPSMate_"..c["name"].."_Head_Font")
|
||||
framePointerCache[k][3] = _G("DPSMate_"..c["name"].."_ScrollFrame_Child")
|
||||
framePointerCache[k][4] = _G("DPSMate_"..c["name"].."_ScrollFrame_Child_Total")
|
||||
for i=1, 40 do
|
||||
framePointerCache[k][4+i] = {}
|
||||
framePointerCache[k][4+i][1] = _G("DPSMate_"..c["name"].."_ScrollFrame_Child_StatusBar"..i)
|
||||
framePointerCache[k][4+i][2] = _G("DPSMate_"..c["name"].."_ScrollFrame_Child_StatusBar"..i.."_Name")
|
||||
framePointerCache[k][4+i][3] = _G("DPSMate_"..c["name"].."_ScrollFrame_Child_StatusBar"..i.."_Value")
|
||||
framePointerCache[k][4+i][4] = _G("DPSMate_"..c["name"].."_ScrollFrame_Child_StatusBar"..i.."_Icon")
|
||||
end
|
||||
end
|
||||
|
||||
local FPC = framePointerCache[k];
|
||||
|
||||
if DPSSettings["showtotals"] then
|
||||
FPC[1]:SetText(strt[1]..strt[2])
|
||||
end
|
||||
if not c["cbtdisplay"] then
|
||||
FPC[2]:SetText(self.Options.Options[1]["args"][c["CurMode"]].name.." ["..self.Options:FormatTime(cbt).."]")
|
||||
end
|
||||
len = 0
|
||||
for i=1, 40 do
|
||||
statusbar = FPC[4+i][1]
|
||||
if user[i] then
|
||||
r,g,b,img = self:GetClassColor(user[i])
|
||||
statusbar:SetStatusBarColor(r,g,b, 1)
|
||||
|
||||
local displayName = user[i]
|
||||
if not DPSMateSettings["mergepets"] and DPSMateUser[user[i]] and DPSMateUser[user[i]][4] then
|
||||
local ownerID = DPSMateUser[user[i]][6]
|
||||
if ownerID then
|
||||
local ownerName = self:GetUserById(ownerID)
|
||||
if ownerName then displayName = user[i].." ("..ownerName..")" end
|
||||
end
|
||||
end
|
||||
if c["ranks"] then
|
||||
FPC[4+i][2]:SetText(i..". "..displayName)
|
||||
else
|
||||
FPC[4+i][2]:SetText(displayName)
|
||||
end
|
||||
FPC[4+i][3]:SetText(val[i])
|
||||
FPC[4+i][4]:SetTexture("Interface\\AddOns\\DPSMate\\images\\class\\"..img)
|
||||
statusbar:SetValue(perc[i])
|
||||
|
||||
statusbar.user = user[i]
|
||||
statusbar:Show()
|
||||
len = len + 1
|
||||
else
|
||||
statusbar:Hide()
|
||||
end
|
||||
end
|
||||
FPC[3]:SetHeight((len+1)*(c["barheight"]+c["barspacing"]))
|
||||
FPC[4]:Show()
|
||||
if len == 0 then
|
||||
FPC[4]:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DPSMate:strrev(str)
|
||||
local res, len = {}, strlen(str)
|
||||
for i=1, len do
|
||||
res[i] = strsub(str, len-i+1, len-i+1)
|
||||
end
|
||||
return tconcat(res);
|
||||
end
|
||||
|
||||
function DPSMate:Commas(n,k)
|
||||
if DPSSettings["windows"][k]["numberformat"] == 3 then
|
||||
n = strformat("%.0f", n)
|
||||
for left, num, right in strgfind(n, '([^%d]*%d)(%d+)') do
|
||||
return left and left..self:strrev(strgsub(self:strrev(num), '(%d%d%d)','%1,'))
|
||||
end
|
||||
end
|
||||
return n;
|
||||
end
|
||||
|
||||
function DPSMate:FormatNumbers(dmg,total,sort,k)
|
||||
local oldd, oldt, olds = dmg, total, sort
|
||||
if DPSSettings["windows"][k]["numberformat"] == 2 then
|
||||
if dmg>10000 then
|
||||
dmg = strformat("%.0f", (dmg/1000))
|
||||
end
|
||||
if total>10000 then
|
||||
total = strformat("%.0f", (total/1000))
|
||||
end
|
||||
if sort>10000 then
|
||||
sort = strformat("%.0f", (sort/1000))
|
||||
end
|
||||
elseif DPSSettings["windows"][k]["numberformat"] == 4 then
|
||||
if dmg>10000 then
|
||||
dmg = strformat("%.1f", (dmg/1000))
|
||||
end
|
||||
if total>10000 then
|
||||
total = strformat("%.1f", (total/1000))
|
||||
end
|
||||
if sort>10000 then
|
||||
sort = strformat("%.1f", (sort/1000))
|
||||
end
|
||||
end
|
||||
return dmg, total, sort, oldd, oldt, olds
|
||||
end
|
||||
|
||||
function DPSMate:ApplyFilter(key, name)
|
||||
if not name or not DPSMateUser[name] then return false end
|
||||
if not key then return true end
|
||||
local class = DPSMateUser[name][2] or "warrior"
|
||||
local path = DPSSettings["windows"][key]
|
||||
if path["grouponly"] then
|
||||
if not DPSMate.Parser.TargetParty[name] and next(DPSMate.Parser.TargetParty) ~= nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if path["filterpeople"] and path["filterpeople"] ~= "" then
|
||||
-- Certain people
|
||||
t = {}
|
||||
strgsub(path["filterpeople"]..",", "(.-),", func)
|
||||
for cat, val in pairs(t) do
|
||||
if name == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- classes
|
||||
for cat, val in pairs(path["filterclasses"]) do
|
||||
if not val then
|
||||
if cat == class then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function DPSMate:GetSettingValues(arr, cbt, k, ecbt)
|
||||
k = k or 1
|
||||
return self.RegistredModules[DPSSettings["windows"][k]["CurMode"]]:GetSettingValues(arr, cbt, k, ecbt)
|
||||
end
|
||||
|
||||
function DPSMate:EvalTable(k)
|
||||
k = k or 1
|
||||
return self.RegistredModules[DPSSettings["windows"][k]["CurMode"]]:EvalTable(DPSMateUser[UnitName("player")], k)
|
||||
end
|
||||
|
||||
function DPSMate:GetClassColor(class)
|
||||
if not class then
|
||||
class = "warrior"
|
||||
end
|
||||
if DPSMateUser[class] then
|
||||
class = DPSMateUser[class][2] or "warrior"
|
||||
end
|
||||
if classcolor[class] then
|
||||
return classcolor[class].r, classcolor[class].g, classcolor[class].b, class
|
||||
end
|
||||
return classcolor["warrior"].r, classcolor["warrior"].g, classcolor["warrior"].b, "warrior"
|
||||
end
|
||||
|
||||
function DPSMate:GetMode(k)
|
||||
k = k or 1
|
||||
local Handler = DPSMate.RegistredModules[DPSSettings["windows"][k]["CurMode"]]
|
||||
local opts = DPSSettings["windows"][k]["options"][2]
|
||||
-- Check in deterministic order: total first, then currentfight, then segments
|
||||
if opts["total"] then
|
||||
return Handler.DB[1], DPSMateCombatTime["total"], DPSMateCombatTime["effective"][1]
|
||||
end
|
||||
if opts["currentfight"] then
|
||||
return Handler.DB[2], DPSMateCombatTime["current"], DPSMateCombatTime["effective"][2]
|
||||
end
|
||||
local num
|
||||
for cat, val in pairs(opts) do
|
||||
if val and strfind(cat, "segment") then
|
||||
num = tonumber(strsub(cat, 8))
|
||||
if (Handler.Hist) and DPSHist[Handler.Hist] and self:TableLength(DPSHist[Handler.Hist]) >= num then
|
||||
return DPSHist[Handler.Hist][num], DPSMateCombatTime["segments"][num][1], DPSMateCombatTime["segments"][num][2]
|
||||
else
|
||||
return {}, 0, 0
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Fallback: default to total
|
||||
return Handler.DB[1], DPSMateCombatTime["total"], DPSMateCombatTime["effective"][1]
|
||||
end
|
||||
|
||||
function DPSMate:GetModeByArr(arr, k, Hist)
|
||||
local opts = DPSSettings["windows"][k]["options"][2]
|
||||
-- Check in deterministic order: total first, then currentfight, then segments
|
||||
if opts["total"] then
|
||||
return arr[1], DPSMateCombatTime["total"], DPSMateCombatTime["effective"][1]
|
||||
end
|
||||
if opts["currentfight"] then
|
||||
return arr[2], DPSMateCombatTime["current"], DPSMateCombatTime["effective"][2]
|
||||
end
|
||||
local num
|
||||
for cat, val in pairs(opts) do
|
||||
if val and strfind(cat, "segment") then
|
||||
num = tonumber(strsub(cat, 8))
|
||||
if (Hist or arr.Hist) and DPSHist[Hist or arr.Hist] and self:TableLength(DPSHist[Hist or arr.Hist]) >= num then
|
||||
return DPSHist[Hist or arr.Hist][num], DPSMateCombatTime["segments"][num][1], DPSMateCombatTime["segments"][num][2]
|
||||
else
|
||||
return {}, 0, 0
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Fallback: default to total
|
||||
return arr[1], DPSMateCombatTime["total"], DPSMateCombatTime["effective"][1]
|
||||
end
|
||||
|
||||
function DPSMate:GetModeName(k)
|
||||
k = k or 1
|
||||
local opts = DPSSettings["windows"][k]["options"][2]
|
||||
if opts["total"] then return "Total" end
|
||||
if opts["currentfight"] then return "Current fight" end
|
||||
local num
|
||||
for cat, val in pairs(opts) do
|
||||
if val and strfind(cat, "segment") then
|
||||
num = tonumber(strsub(cat, 8))
|
||||
return DPSHist["names"][num]
|
||||
end
|
||||
end
|
||||
return "Total"
|
||||
end
|
||||
|
||||
function DPSMate:Disable()
|
||||
if self.Registered then
|
||||
self.Sync:UnregisterEvent("CHAT_MSG_ADDON")
|
||||
for _, event in pairs(self.Events) do
|
||||
self.Parser:UnregisterEvent(event)
|
||||
end
|
||||
self.Registered = false
|
||||
end
|
||||
end
|
||||
|
||||
function DPSMate:Enable()
|
||||
if not self.Registered then
|
||||
self.Sync:RegisterEvent("CHAT_MSG_ADDON")
|
||||
for _, val in pairs(self.RegistredModules) do
|
||||
if val.Events then
|
||||
for _, event in pairs(val.Events) do
|
||||
self.Parser:RegisterEvent(event)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.Registered = true
|
||||
end
|
||||
end
|
||||
|
||||
function DPSMate:Broadcast(type, who, what, with, value, failtype)
|
||||
if DPSSettings["broadcasting"] then
|
||||
if IsRaidLeader() or IsRaidOfficer() then
|
||||
local ch = "RAID"
|
||||
if DPSSettings["bcrw"] then
|
||||
ch = "RAID_WARNING"
|
||||
end
|
||||
if DPSSettings["bccd"] and type == 1 then
|
||||
SendChatMessage("BULK", "DPSMateChat", self.L["bccdo"](who, what), ch, nil, nil)
|
||||
return
|
||||
elseif DPSSettings["bccd"] and type == 6 then
|
||||
SendChatMessage("BULK", "DPSMateChat", self.L["bccdt"](who, what), ch, nil, nil)
|
||||
return
|
||||
elseif DPSSettings["bcress"] and type == 2 then
|
||||
SendChatMessage("BULK", "DPSMateChat", self.L["bcress"](who, what), ch, nil, nil)
|
||||
return
|
||||
elseif DPSSettings["bckb"] and type == 4 then
|
||||
SendChatMessage("BULK", "DPSMateChat", self.L["bckb"](who, what, with, value), ch, nil, nil)
|
||||
return
|
||||
elseif DPSSettings["bcfail"] and type == 3 then
|
||||
if failtype == 1 then
|
||||
SendChatMessage("BULK", "DPSMateChat", self.L["bcfailo"](what, who, value, with), ch, nil, nil)
|
||||
elseif failtype == 3 then
|
||||
SendChatMessage("BULK", "DPSMateChat", self.L["bcfailt"](who, with), ch, nil, nil)
|
||||
else
|
||||
SendChatMessage("BULK", "DPSMateChat", self.L["bcfailth"](who, value, with, what), ch, nil, nil)
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DPSMate:SendMessage(msg)
|
||||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF8080"..self.L["name"].."|r: "..msg)
|
||||
end
|
||||
|
||||
function DPSMate:Register(prefix, table, name)
|
||||
self.ModuleNames[name] = prefix
|
||||
self.RegistredModules[prefix] = table
|
||||
end
|
||||
Reference in New Issue
Block a user