You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
845 lines
25 KiB
845 lines
25 KiB
---------------------------------------------------------------------------------
|
|
--
|
|
-- Prat - A framework for World of Warcraft chat modification
|
|
-- and a collection of modules which utilize the framework
|
|
--
|
|
-- Copyright (C) 2006-2020 Prat Development Team
|
|
--
|
|
-- This program is free software; you can redistribute it and/or
|
|
-- modify it under the terms of the GNU General Public License
|
|
-- as published by the Free Software Foundation; either version 2
|
|
-- of the License, or (at your option) any later version.
|
|
--
|
|
-- This program is distributed in the hope that it will be useful,
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-- GNU General Public License for more details.
|
|
--
|
|
-- You should have received a copy of the GNU General Public License
|
|
-- along with this program; if not, write to:
|
|
--
|
|
-- Free Software Foundation, Inc.,
|
|
-- 51 Franklin Street, Fifth Floor,
|
|
-- Boston, MA 02110-1301, USA.
|
|
--
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
Prat = select(2, ...)
|
|
|
|
--[[ BEGIN STANDARD HEADER ]] --
|
|
|
|
-- Imports
|
|
local _G = _G
|
|
local LibStub = LibStub
|
|
local tonumber = tonumber
|
|
local tostring = tostring
|
|
local pairs = pairs
|
|
local ipairs = ipairs
|
|
local type = type
|
|
local select = select
|
|
local tinsert = tinsert
|
|
local Prat = Prat
|
|
local setmetatable, getmetatable = setmetatable, getmetatable
|
|
local strfind = strfind
|
|
local IsSecureCmd = IsSecureCmd
|
|
local wipe = table.wipe
|
|
local print = print
|
|
|
|
--[[ END STANDARD HEADER ]] --
|
|
|
|
--NEW_CHATFILTERS = select(4, _G.GetBuildInfo()) >= 30100
|
|
--CHAT_PLAYER_GUIDS = select(4, _G.GetBuildInfo()) >= 30200
|
|
--MOP = select(4, _G.GetBuildInfo()) >= 50000
|
|
|
|
Prat.BN_CHAT = true --(_G.GetBuildInfo() == "3.3.5") or (_G.GetBuildInfo() == "0.3.5")
|
|
|
|
-- Debug
|
|
--PrintMainChunkUse=true
|
|
|
|
|
|
--ChunkSizes = {}
|
|
|
|
--[==[@debug@
|
|
Prat.Version = "Prat |cff8080ff3.0|r (|cff8080ff" .. "DEBUG" .. "|r)"
|
|
|
|
|
|
--@end-debug@]==]
|
|
|
|
--@non-debug@
|
|
Prat.Version = "Prat |cff8080ff3.0|r (|cff8080ff".."3.9.55".."|r)"
|
|
--@end-non-debug@
|
|
|
|
|
|
local am = {}
|
|
local om = getmetatable(Prat)
|
|
if om then
|
|
for k, v in pairs(om) do am[k] = v end
|
|
end
|
|
am.__tostring = function() return "Prat |cff8080ff3.0|r" end
|
|
setmetatable(Prat, am)
|
|
|
|
|
|
Prat.Prat3 = true
|
|
Prat.IsClassic = (_G.WOW_PROJECT_ID ~= _G.WOW_PROJECT_MAINLINE)
|
|
Prat.IsRetail = (_G.WOW_PROJECT_ID == _G.WOW_PROJECT_MAINLINE)
|
|
|
|
|
|
local function dbg(...) end
|
|
|
|
--[==[@debug@
|
|
local function dbg(...) Prat:PrintLiteral(...) end
|
|
|
|
--@end-debug@]==]
|
|
|
|
Prat.Localizations = Prat.GetLocalizer({})
|
|
local L = Prat.Localizations
|
|
|
|
Prat.Frames = {
|
|
["ChatFrame1"] = _G.ChatFrame1,
|
|
["ChatFrame2"] = _G.ChatFrame2,
|
|
["ChatFrame3"] = _G.ChatFrame3,
|
|
["ChatFrame4"] = _G.ChatFrame4,
|
|
["ChatFrame5"] = _G.ChatFrame5,
|
|
["ChatFrame6"] = _G.ChatFrame6,
|
|
["ChatFrame7"] = _G.ChatFrame7,
|
|
["ChatFrame8"] = _G.ChatFrame8,
|
|
["ChatFrame9"] = _G.ChatFrame9,
|
|
["ChatFrame10"] = _G.ChatFrame10
|
|
}
|
|
Prat.HookedFrames = {}
|
|
|
|
Prat.ExternalFrames = {}
|
|
|
|
|
|
local builtinSounds = {
|
|
["Bell"] = "Interface\\AddOns\\Prat-3.0\\sounds\\Bell.ogg",
|
|
["Chime"] = "Interface\\AddOns\\Prat-3.0\\Sounds\\Chime.ogg",
|
|
["Heart"] = "Interface\\AddOns\\Prat-3.0\\Sounds\\Heart.ogg",
|
|
["IM"] = "Interface\\AddOns\\Prat-3.0\\Sounds\\IM.ogg",
|
|
["Info"] = "Interface\\AddOns\\Prat-3.0\\Sounds\\Info.ogg",
|
|
["Kachink"] = "Interface\\AddOns\\Prat-3.0\\Sounds\\Kachink.ogg",
|
|
["popup"] = "Interface\\AddOns\\Prat-3.0\\Sounds\\Link.ogg",
|
|
["Text1"] = "Interface\\AddOns\\Prat-3.0\\Sounds\\Text1.ogg",
|
|
["Text2"] = "Interface\\AddOns\\Prat-3.0\\Sounds\\Text2.ogg",
|
|
["Xylo"] = "Interface\\AddOns\\Prat-3.0\\Sounds\\Xylo.ogg",
|
|
}
|
|
|
|
|
|
-- Symbolic names for all the events which Prat uses
|
|
Prat.Events = {
|
|
MODULE_ENABLED = "Prat_ModuleCreated",
|
|
DISABLED = "Prat_Disabled",
|
|
ENABLING = "Prat_Starting",
|
|
ENABLED = "Prat_Ready",
|
|
STARTUP = "Prat_Initialized",
|
|
DEBUG_UPDATE = "Prat_DebugModeChanged",
|
|
PRE_OUTBOUND = "Prat_PreOutboundChat",
|
|
OUTBOUND = "Prat_OutboundChat",
|
|
PRE_ADDMESSAGE = "Prat_PreAddMessage",
|
|
POST_ADDMESSAGE = "Prat_PostAddMessage",
|
|
POST_ADDMESSAGE_BLOCKED = "Prat_PostAddMessageBlocked",
|
|
FRAME_MESSAGE = "Prat_FrameMessage",
|
|
SECTIONS_UPDATED = "Prat_ChatSectionsUpdated",
|
|
FRAMES_UPDATED = "Prat_FramesUpdated",
|
|
FRAMES_REMOVED = "Prat_FramesRemoved",
|
|
}
|
|
|
|
Prat.EnableTasks = {}
|
|
|
|
local addon = LibStub("AceAddon-3.0"):NewAddon("Prat", "AceConsole-3.0", "AceTimer-3.0", "AceHook-3.0")
|
|
Prat.Addon = addon
|
|
|
|
--local callbacks
|
|
|
|
--[[ 1 = no load, 2 = disabled, 3 = enabled (this is temporary, a better format will be forthcoming, 4 is setdisabled, and 5 is setenabled]]
|
|
-- What I need to do is return the module's own value if the option isn't 1
|
|
-- but one problem is if the module was "no-load", and then is set to "enabled" but it thinks it should be "disabled"
|
|
local defaults = {
|
|
profile = {
|
|
modules = {
|
|
["Clear"] = 1,
|
|
["AddonMsgs"] = 1,
|
|
["CustomFilters"] = 1,
|
|
["EventNames"] = 1,
|
|
["Substitutions"] = 1,
|
|
["Experimental"] = 1,
|
|
["Filtering"] = 1,
|
|
["KeyBindings"] = 3,
|
|
["OriginalEditbox"] = 1,
|
|
["ChatTabs"] = 1,
|
|
["*"] = 3
|
|
}
|
|
},
|
|
realm = {
|
|
PlayerNameBlackList = {
|
|
["you"] = true
|
|
}
|
|
}
|
|
}
|
|
local SOUND
|
|
function addon:OnInitialize()
|
|
local IsAddOnLoaded = _G.C_AddOns.IsAddOnLoaded or _G.IsAddOnLoaded
|
|
if IsAddOnLoaded("Prat") == 1 then
|
|
Prat:Print(("Prat 2.0 was detected, and disabled. Please %s your UI."):format(GetReloadUILink()))
|
|
end
|
|
|
|
|
|
Prat.db = LibStub("AceDB-3.0"):New("Prat3DB", defaults, "Default")
|
|
|
|
_G.Prat3CharDB = _G.Prat3CharDB or {}
|
|
|
|
Prat.PlayerNameBlackList = Prat.db.realm.PlayerNameBlackList or {}
|
|
|
|
Prat.callbacks = LibStub("CallbackHandler-1.0"):New(Prat, "RegisterChatEvent", "UnregisterChatEvent", "UnregisterAllChatEvents")
|
|
|
|
Prat.Options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(Prat.db)
|
|
Prat.Options.args.profiles.order = tonumber(-1)
|
|
|
|
Prat.Media = LibStub("LibSharedMedia-3.0")
|
|
SOUND = Prat.Media.MediaType.SOUND
|
|
|
|
for k, v in pairs(builtinSounds) do
|
|
Prat.Media:Register(SOUND, k, v)
|
|
end
|
|
|
|
Prat.AddonName = self.baseName
|
|
|
|
Prat.builtinSounds = nil
|
|
|
|
|
|
-- Build the list of frames which we should hook addmessage on
|
|
-- IsCombatLog is not correct yet it appears, so we resort to checking
|
|
-- for chatframe2
|
|
for _, v in pairs(Prat.Frames) do
|
|
if (not _G.IsCombatLog(v)) and v ~= _G.ChatFrame2 then
|
|
Prat.HookedFrames[v:GetName()] = v
|
|
end
|
|
end
|
|
|
|
|
|
Prat.db.RegisterCallback(self, "OnProfileChanged", "UpdateProfile")
|
|
Prat.db.RegisterCallback(self, "OnProfileCopied", "UpdateProfile")
|
|
Prat.db.RegisterCallback(self, "OnProfileReset", "UpdateProfile")
|
|
|
|
-- _G.collectgarbage('collect')
|
|
-- Print("Pre-Module-Load Memory Use: "..MemoryUse())
|
|
|
|
Prat.LoadModules()
|
|
|
|
-- _G.collectgarbage('collect')
|
|
-- Print("Post-Module-Load Memory Use: "..MemoryUse())
|
|
|
|
self.OnInitalize = nil
|
|
end
|
|
|
|
local DEF_INFO = {
|
|
r = 1,
|
|
g = 1,
|
|
b = 1,
|
|
id = 1
|
|
}
|
|
|
|
-- Used for Prat/WIM integration
|
|
function Prat.Format(smf, event, color, ...)
|
|
local PRE_ADDMESSAGE = "Prat_PreAddMessage"
|
|
local POST_ADDMESSAGE = "Prat_PostAddMessage"
|
|
local FRAME_MESSAGE = "Prat_FrameMessage"
|
|
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15 = ...;
|
|
local this = smf
|
|
local formattedText = ""
|
|
local m, info = Prat.SplitChatMessage(smf, event, ...)
|
|
|
|
if type(m) == "boolean" and m == true then
|
|
return ""
|
|
end
|
|
|
|
Prat.CurrentMessage = m
|
|
|
|
m.DONOTPROCESS = nil
|
|
local process = Prat.EventProcessingType.Full
|
|
|
|
Prat.callbacks:Fire(FRAME_MESSAGE, m, this, event)
|
|
|
|
if not m.DONOTPROCESS then
|
|
color = color or info
|
|
local r, g, b, id = color.r or 1, color.g or 1, color.b or 1, 1
|
|
|
|
-- Remove all the pattern matches ahead of time
|
|
m.MESSAGE = Prat.MatchPatterns(m)
|
|
|
|
Prat.callbacks:Fire(PRE_ADDMESSAGE, m, this, event, Prat.BuildChatText(m), r, g, b, id)
|
|
|
|
-- Pattern Matches Put Back IN
|
|
m.MESSAGE = Prat.ReplaceMatches(m)
|
|
|
|
if process == Prat.EventProcessingType.Full then
|
|
-- We are about to send the message
|
|
m.OUTPUT = Prat.BuildChatText(m) -- Combine all the chat sections
|
|
elseif process == Prat.EventProcessingType.PatternsOnly then
|
|
|
|
m.OUTPUT = (m.PRE or "") .. m.MESSAGE .. (m.POST or "")
|
|
else
|
|
if type(m.OUTPUT) == "string" then
|
|
-- Now we have the chatstring that the client was planning to output
|
|
-- For now just do it. (Tack on POST too)
|
|
m.OUTPUT = (m.PRE or "") .. m.OUTPUT .. (m.POST or "")
|
|
end
|
|
end
|
|
|
|
-- Allow for message blocking during the patern match phase
|
|
if not m.DONOTPROCESS then
|
|
formattedText = m.OUTPUT
|
|
end
|
|
|
|
-- We have called addmessage by now, or we have skipped it
|
|
-- regardless, we call postaddmessage. This was changed to allow
|
|
-- for more flexibility in the customfilters module, speficially
|
|
-- it allows for replacements to occur in blocked messages
|
|
|
|
Prat.callbacks:Fire(POST_ADDMESSAGE, m, this, event, m.OUTPUT, r, g, b, id)
|
|
end
|
|
|
|
m.CAPTUREOUTPUT = nil
|
|
m.OUTPUT = nil
|
|
m.INFO = nil
|
|
|
|
Prat.CurrentMessage = nil
|
|
|
|
return formattedText
|
|
end
|
|
|
|
function addon:OnEnable()
|
|
for i, v in ipairs(Prat.EnableTasks) do
|
|
v(self)
|
|
end
|
|
Prat.EnableTasks = nil
|
|
|
|
Prat.RegisterLinkType({
|
|
linkid = "rldui",
|
|
linkfunc = function(...) _G.ReloadUI() return false end
|
|
}, "Prat")
|
|
|
|
self:PostEnable()
|
|
end
|
|
|
|
|
|
function addon:UpdateProfile()
|
|
self:ScheduleTimer("UpdateProfileDelayed", 0)
|
|
end
|
|
|
|
function addon:UpdateProfileDelayed()
|
|
for k, v in self:IterateModules() do
|
|
if v.db.profile.on then
|
|
if v:IsEnabled() then
|
|
v:Disable()
|
|
v:Enable()
|
|
else
|
|
v:Enable()
|
|
end
|
|
else
|
|
v:Disable()
|
|
end
|
|
end
|
|
|
|
Prat.UpdateOptions()
|
|
end
|
|
|
|
function Prat.GetReloadUILink(Requestor)
|
|
return "Reload"
|
|
end
|
|
|
|
local module = {}
|
|
|
|
do
|
|
local org_GetChannelName = _G.GetChannelName
|
|
local chanTable
|
|
Prat.EnableTasks[#Prat.EnableTasks + 1] = function() chanTable = Prat.GetChannelTable() end
|
|
function Prat.GetChannelName(n)
|
|
local a, b, c = org_GetChannelName(n)
|
|
|
|
--dbg("GetChannelName: "..tostring(n), a,b,c)
|
|
|
|
if b == nil and chanTable then
|
|
n = chanTable[n]
|
|
|
|
if n ~= nil then
|
|
a, b, c = org_GetChannelName(n)
|
|
|
|
--dbg("GetChannelName: "..n, a,b,c)
|
|
end
|
|
end
|
|
|
|
return a, b, c
|
|
end
|
|
|
|
-- Orignial GetChannelName
|
|
--Prat 3.0 (244): >> print(GetChannelName(1))
|
|
--Prat 3.0 (244): 1, "General - The Storm Peaks", 0
|
|
--Prat 3.0 (244): >> print(GetChannelName("General"))
|
|
--Prat 3.0 (244): 0, nil, 0
|
|
|
|
-- Replace the global version with one which sucks a bit less
|
|
--_G.GetChannelName = GetChannelName
|
|
|
|
-- Improved GetChannelName
|
|
--Prat 3.0 (244): >> print(GetChannelName(1))
|
|
--Prat 3.0 (244): 1, "General - The Storm Peaks", 0
|
|
--Prat 3.0 (244): >> print(GetChannelName("General"))
|
|
--Prat 3.0 (244): 1, "General - The Storm Peaks", 0
|
|
end
|
|
|
|
function addon:FCF_SetTemporaryWindowType(chatFrame, chatType, chatTarget)
|
|
local name = chatFrame:GetName()
|
|
|
|
Prat.Frames[name] = chatFrame
|
|
|
|
Prat.HookedFrames[name] = chatFrame
|
|
|
|
Prat.callbacks:Fire(Prat.Events.FRAMES_UPDATED, name, chatFrame, chatType, chatTarget)
|
|
end
|
|
|
|
|
|
function addon:FCF_Close(frame, fallback)
|
|
local name = frame:GetName()
|
|
|
|
Prat.Frames[name] = nil
|
|
|
|
Prat.HookedFrames[name] = nil
|
|
|
|
Prat.callbacks:Fire(Prat.Events.FRAMES_REMOVED, name, frame)
|
|
end
|
|
|
|
function addon:FCF_CopyChatSettings(chatFrame)
|
|
if not chatFrame.isTemporary then
|
|
local name = chatFrame:GetName()
|
|
|
|
Prat.Frames[name] = chatFrame
|
|
|
|
if not _G.IsCombatLog(chatFrame) then
|
|
Prat.HookedFrames[name] = chatFrame
|
|
end
|
|
|
|
Prat.callbacks:Fire(Prat.Events.FRAMES_UPDATED, name, chatFrame)
|
|
end
|
|
end
|
|
|
|
function addon:PostEnable()
|
|
--[==[@debug@
|
|
Prat:Print(Prat.Version)
|
|
--@end-debug@]==]
|
|
|
|
Prat.AddPrintMethods()
|
|
|
|
if Prat.PrintSlashCommand then
|
|
self:RegisterChatCommand("print", Prat.PrintSlashCommand)
|
|
end
|
|
-- 2.4 Changes
|
|
-- self:RegisterEvent("CVAR_UPDATE")
|
|
|
|
-- Inbound Hooking
|
|
self:RawHook("ChatFrame_MessageEventHandler", true)
|
|
|
|
-- Outbound hooking
|
|
self:SecureHook("ChatEdit_ParseText")
|
|
|
|
-- Display Hooking
|
|
Prat.DummyFrame = _G.CreateFrame("ScrollingMessageFrame")
|
|
self:RawHook(Prat.DummyFrame, "AddMessage", true)
|
|
|
|
-- ItemRef Hooking
|
|
|
|
self:RawHook(_G.ItemRefTooltip, "SetHyperlink", true)
|
|
|
|
self:SecureHook("FCF_SetTemporaryWindowType")
|
|
|
|
self:SecureHook("FCF_Close")
|
|
|
|
self:SecureHook("FCF_CopyChatSettings")
|
|
|
|
-- -- This event fires after Prat's hooks are installed
|
|
-- -- Prat's core wont operate until after this event
|
|
Prat.callbacks:Fire(Prat.Events.SECTIONS_UPDATED)
|
|
Prat.callbacks:Fire(Prat.Events.ENABLED)
|
|
|
|
--[==[@debug@
|
|
|
|
-- if ChunkSizes then
|
|
-- local last = 0
|
|
-- for i, v in ipairs(ChunkSizes) do
|
|
-- self:Print("Chunk #"..tostring(i)..":"..("|cff80ffff%.0f|r KB"):format(v-last))
|
|
-- last = v
|
|
-- end
|
|
-- self:Print("Total Size: "..("|cff80ffff%.0f|r KB"):format(ChunkSizes[#ChunkSizes]))
|
|
-- ChunkSizes = nil
|
|
-- end
|
|
|
|
if Prat.Modules then
|
|
local total, loaded, enabled = 0, 0, 0
|
|
for k, v in pairs(Prat.Modules) do
|
|
total = total + 1
|
|
if v ~= "EXISTS" then
|
|
loaded = loaded + 1
|
|
end
|
|
if v == "ENABLED" then
|
|
enabled = enabled + 1
|
|
end
|
|
end
|
|
|
|
Prat:Print(("Module Count: |cff80ffff%d|r total |cff80ffff%d|r loaded, |cff80ffff%d|r enabled"):format(total, loaded, enabled))
|
|
end
|
|
|
|
if Prat.MemoryUse then
|
|
_G.collectgarbage("collect")
|
|
Prat:Print("Memory Use: " .. Prat.MemoryUse())
|
|
end
|
|
--@end-debug@]==]
|
|
|
|
if Prat.EnableGlobalCompletions then
|
|
Prat.EnableGlobalCompletions(Prat, "Prat-Global-Autocomplete")
|
|
end
|
|
end
|
|
|
|
function addon:SetHyperlink(frame, ...)
|
|
return Prat.SetHyperlinkHook(self.hooks[frame], frame, ...)
|
|
end
|
|
|
|
|
|
function addon:ChatEdit_ParseText(editBox, send)
|
|
local command = editBox:GetText()
|
|
|
|
-- this is what blizzard does
|
|
local cmd = command:match("^(#%s*[Ss][Hh][Oo][Ww]:*)%s[^%s]") or
|
|
command:match("^(#%s*[Ss][Hh][Oo][Ww][Tt][Oo][Oo][Ll][Tt][Ii][Pp]:*)%s[^%s]") or
|
|
command:match("^(/[^%s]+)");
|
|
|
|
-- Hack from blizzard's code
|
|
if (cmd and strfind(cmd, "^#")) then
|
|
-- This is a hack, but the "USE" code below handles bags and slots
|
|
cmd = SLASH_USE1;
|
|
end
|
|
|
|
if cmd and IsSecureCmd(cmd) then
|
|
return
|
|
end
|
|
|
|
local m = Prat.SplitMessageOut
|
|
wipe(m)
|
|
CurrentMessage = m
|
|
|
|
|
|
m.MESSAGE = command:gsub("^%s*(.-)%s*$", "%1") -- trim whitespace
|
|
|
|
m.CTYPE = editBox:GetAttribute("chatType")
|
|
m.TARGET = editBox:GetAttribute("tellTarget")
|
|
m.CHANNEL = editBox:GetAttribute("channelTarget")
|
|
m.LANGUAGE = editBox.language
|
|
m.SEND = send
|
|
|
|
if send ~= 1 then
|
|
return
|
|
end
|
|
|
|
self:ProcessUserEnteredChat(m)
|
|
|
|
editBox:SetAttribute("chatType", m.CTYPE)
|
|
editBox:SetAttribute("tellTarget", m.TARGET)
|
|
editBox:SetAttribute("channelTarget", m.CHANNEL)
|
|
editBox.languague = m.LANGUAGE
|
|
|
|
|
|
if m.DONOTPROCESS then
|
|
editBox:SetText("")
|
|
else
|
|
editBox:SetText(m.MESSAGE)
|
|
end
|
|
|
|
Prat.CurrentMessage = nil
|
|
end
|
|
|
|
|
|
function addon:ProcessUserEnteredChat(m)
|
|
if (m.MESSAGE:len() <= 0) then
|
|
return
|
|
end
|
|
|
|
Prat.callbacks:Fire(Prat.Events.PRE_OUTBOUND, m)
|
|
|
|
-- Remove all the pattern matches ahead of time
|
|
m.MESSAGE = Prat.MatchPatterns(m, "OUTBOUND")
|
|
|
|
Prat.callbacks:Fire(Prat.Events.OUTBOUND, m)
|
|
|
|
-- Pattern Matches Put Back IN
|
|
m.MESSAGE = Prat.ReplaceMatches(m, "OUTBOUND")
|
|
end
|
|
|
|
local fieldBlacklist = {
|
|
historyBuffer = true,
|
|
isLayoutDirty = true,
|
|
isDisplayDirty = true,
|
|
onDisplayRefreshedCallback = true,
|
|
onScrollChangedCallback = true,
|
|
onTextCopiedCallback = true,
|
|
scrollOffset = true,
|
|
visibleLines = true,
|
|
highlightTexturePool = true,
|
|
fontStringPool = true,
|
|
}
|
|
local savedFrame = {}
|
|
function Prat.CreateProxy(frame)
|
|
for k, v in pairs(frame) do
|
|
if type(v) ~= "function" and not fieldBlacklist[k] then
|
|
savedFrame[k] = Prat.DummyFrame[k]
|
|
Prat.DummyFrame[k] = v
|
|
end
|
|
end
|
|
Prat.DummyFrame.IsShown = function() return true end
|
|
return Prat.DummyFrame
|
|
end
|
|
|
|
function Prat.RestoreProxy()
|
|
for k, v in pairs(savedFrame) do
|
|
Prat.DummyFrame[k] = v
|
|
end
|
|
for k, v in pairs(Prat.DummyFrame) do
|
|
if type(v) ~= "function" and not fieldBlacklist[k] then
|
|
if savedFrame[k] == nil then
|
|
Prat.DummyFrame[k] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function addon:ChatFrame_MessageEventHandler(this, event, ...)
|
|
local PRE_ADDMESSAGE = "Prat_PreAddMessage"
|
|
local POST_ADDMESSAGE = "Prat_PostAddMessage"
|
|
local FRAME_MESSAGE = "Prat_FrameMessage"
|
|
local POST_ADDMESSAGE_BLOCKED = "Prat_PostAddMessageBlocked"
|
|
|
|
|
|
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15 = ...
|
|
|
|
loading = nil -- clear any batch message loading that may be happening
|
|
|
|
if not Prat.HookedFrames[this:GetName()] then
|
|
return self.hooks["ChatFrame_MessageEventHandler"](this, event, ...)
|
|
end
|
|
|
|
local message, info
|
|
local process = Prat.EventIsProcessed(event)
|
|
|
|
local CMEResult
|
|
|
|
if type(arg1) == "string" and (arg1):find("\r") then -- Stupid exploit. Protect our users.
|
|
arg1 = arg1:gsub("\r", " ")
|
|
end
|
|
|
|
-- Create a message table. This table contains the chat message in a non-concatenated form
|
|
-- so that it can be modified easily without lots of complex gsub's
|
|
message, info = Prat.SplitChatMessage(this, event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15)
|
|
|
|
-- Handle Default-UI filtering: Since the default UI now provides filtering functions
|
|
-- similar to the way Prat's pattern registry works, we need to be sure not to call the
|
|
-- filtering functions twice by calling back into the hook chain - otherwise you could
|
|
-- have side effects of the handler functions being called more than once for a given event.
|
|
-- I don't see any way around this.
|
|
if type(message) == "boolean" and message == true then
|
|
return true
|
|
end
|
|
|
|
if not info then
|
|
return self.hooks["ChatFrame_MessageEventHandler"](this, event, ...)
|
|
else
|
|
local m = message --SplitMessage
|
|
|
|
|
|
-- Prat_FrameMessage is fired for every message going to the
|
|
-- chatframe which is displayable (has a chat infotype)
|
|
-- It may not be displayed, in which case no Pre/Post Addmessage
|
|
-- events will fire
|
|
-- Any addons which hook things will operate following this event
|
|
-- but before Prat_PreAddMessage, OUTPUT will contain the chat line
|
|
-- it may be modified by other addons.
|
|
--
|
|
-- Right now, prat will discard the chat line for chat types that
|
|
-- it is handling
|
|
--
|
|
m.OUTPUT = nil
|
|
|
|
m.DONOTPROCESS = nil
|
|
|
|
-- DUMP_OUTPUT_EX(this, "Prat_FrameMessage", nil, nil, m.CAPTUREOUTPUT, m.OUTPUT)
|
|
|
|
Prat.callbacks:Fire(FRAME_MESSAGE, message, this, message.EVENT)
|
|
|
|
-- A return value of true means that the message was processed
|
|
-- normally this would result in the OnEvent returning
|
|
-- for that chatframe
|
|
local proxy = Prat.CreateProxy(this)
|
|
|
|
m.CAPTUREOUTPUT = proxy
|
|
CMEResult = self.hooks["ChatFrame_MessageEventHandler"](proxy, event, ...) -- This specifically does not use message.EVENT
|
|
this.tellTimer = proxy.tellTimer
|
|
|
|
Prat.RestoreProxy()
|
|
|
|
m.CAPTUREOUTPUT = false
|
|
|
|
-- DBG_OUTPUT("CMEResult", CMEResult)
|
|
if type(m.OUTPUT) == "string" and not m.DONOTPROCESS then
|
|
Prat.CurrentMessage = m
|
|
local r, g, b, id = m.INFO.r, m.INFO.g, m.INFO.b, m.INFO.id
|
|
|
|
if process == Prat.EventProcessingType.Full or process == Prat.EventProcessingType.PatternsOnly then
|
|
-- Remove all the pattern matches ahead of time
|
|
m.MESSAGE = Prat.MatchPatterns(m, "FRAME")
|
|
end
|
|
|
|
Prat.callbacks:Fire(PRE_ADDMESSAGE, message, this, message.EVENT, Prat.BuildChatText(message), r, g, b, id)
|
|
|
|
if process == Prat.EventProcessingType.Full or process == Prat.EventProcessingType.PatternsOnly then
|
|
-- Pattern Matches Put Back IN
|
|
m.MESSAGE = Prat.ReplaceMatches(m, "FRAME")
|
|
end
|
|
|
|
if process == Prat.EventProcessingType.Full then
|
|
-- We are about to send the message
|
|
m.OUTPUT = Prat.BuildChatText(message) -- Combine all the chat sections
|
|
elseif process == Prat.EventProcessingType.PatternsOnly then
|
|
|
|
m.OUTPUT = (m.PRE or "") .. m.MESSAGE .. (m.POST or "")
|
|
else
|
|
|
|
-- Now we have the chatstring that the client was planning to output
|
|
-- For now just do it. (Tack on POST too)
|
|
m.OUTPUT = (m.PRE or "") .. m.OUTPUT .. (m.POST or "")
|
|
end
|
|
|
|
-- Allow for message blocking during the patern match phase
|
|
if m.DONOTPROCESS then
|
|
Prat.callbacks:Fire(POST_ADDMESSAGE_BLOCKED, m, this, message.EVENT, m.OUTPUT, r, g, b, id)
|
|
elseif m.OUTPUT:len() > 0 then
|
|
|
|
-- Hack to get the censored message display working with Prat
|
|
local isChatLineCensored = arg11 and C_ChatInfo.IsChatLineCensored(arg11);
|
|
local msg = isChatLineCensored and arg1 or m.OUTPUT
|
|
|
|
if isChatLineCensored then
|
|
local eventLabel = event
|
|
local eventArgs = SafePack(...);
|
|
this:AddMessage(msg, r, g, b, id, m.ACCESSID, m.TYPEID, eventLabel, eventArgs, function(text) return text end);
|
|
else
|
|
this:AddMessage(msg, r, g, b, id, m.ACCESSID, m.TYPEID);
|
|
end
|
|
|
|
-- We have called addmessage by now, or we have skipped it
|
|
-- regardless, we call postaddmessage. This was changed to allow
|
|
-- for more flexibility in the customfilters module, speficially
|
|
-- it allows for replacements to occur in blocked messages
|
|
|
|
Prat.callbacks:Fire(POST_ADDMESSAGE, m, this, message.EVENT, m.OUTPUT, r, g, b, id, m.ACCESSID, m.TYPEID)
|
|
|
|
if (not this:IsShown()) then
|
|
if ((this == _G.DEFAULT_CHAT_FRAME and m.INFO.flashTabOnGeneral) or (this ~= _G.DEFAULT_CHAT_FRAME and m.INFO.flashTab)) then
|
|
if (not _G.CHAT_OPTIONS.HIDE_FRAME_ALERTS or m.CHATTYPE == "WHISPER" or m.CHATTYPE == "BN_WHISPER") then --BN_WHISPER FIXME
|
|
if (not _G.FCFManager_ShouldSuppressMessageFlash(this, m.CHATGROUP, m.CHATTARGET)) then
|
|
_G.FCF_StartAlertFlash(this);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
Prat.LastMessage = m
|
|
end
|
|
end
|
|
|
|
m.CAPTUREOUTPUT = nil
|
|
|
|
Prat.CurrentMessage = nil
|
|
end
|
|
|
|
return CMEResult
|
|
end
|
|
|
|
function addon:AddMessage(frame, text, r, g, b, id, ...)
|
|
local s = Prat.SplitMessage
|
|
if s.OUTPUT == nil and s.CAPTUREOUTPUT == frame --[[ and Prat.dumping == false]] then
|
|
-- s.INFO.r, s.INFO.g, s.INFO.b, s.INFO.id = r, g, b, id
|
|
s.ORG.OUTPUT = text
|
|
else
|
|
self.hooks[frame].AddMessage(frame, text, r, g, b, id, ...)
|
|
end
|
|
end
|
|
|
|
local wowsounds = {
|
|
["TellMessage"] = _G.SOUNDKIT.TELL_MESSAGE,
|
|
}
|
|
|
|
function Prat.PlaySound(self, sound)
|
|
if not sound then return end
|
|
|
|
if wowsounds[sound] then
|
|
_G.PlaySound(wowsounds[sound], "Master")
|
|
else
|
|
local play
|
|
if play == nil then
|
|
play = Prat.Media:Fetch(SOUND, sound)
|
|
end
|
|
if play == nil then return end
|
|
|
|
_G.PlaySoundFile(play, "Master")
|
|
end
|
|
end
|
|
|
|
function Prat.CanSendChatMessage(type)
|
|
if type == "SAY" or type == "YELL" then
|
|
return _G.IsInInstance("player")
|
|
elseif type == "RAID" or type == "GUILD" or type == "WHISPER" then
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
|
|
function Prat.RegisterChatCommand(cmd, func)
|
|
addon:RegisterChatCommand(cmd, func)
|
|
end
|
|
|
|
|
|
Prat.RegisterChatCommand("pratblacklist",
|
|
function(name)
|
|
if name and #name > 0 then
|
|
Prat:Print("Blacklisting: '" .. tostring(name) .. "' to activate " .. Prat.GetReloadUILink())
|
|
db.realm.PlayerNameBlackList[tostring(name):lower()] = true
|
|
end
|
|
end)
|
|
|
|
|
|
Prat.RegisterChatCommand("pratunblacklist",
|
|
function(name)
|
|
if name and #name > 0 then
|
|
Prat:Print("Un-Blacklisting: '" .. tostring(name) .. "' to activate " .. Prat.GetReloadUILink())
|
|
db.realm.PlayerNameBlackList[tostring(name):lower()] = nil
|
|
end
|
|
end)
|
|
|
|
|
|
Prat.RegisterChatCommand("pratdebugmsg",
|
|
function(name)
|
|
Prat:PrintLiteral(LastMessage, Prat.LastMessage.ORG)
|
|
|
|
local cc = addon:GetModule("CopyChat", true)
|
|
if cc then cc:ScrapeFullChatFrame(printFrame or _G.DEFAULT_CHAT_FRAME, true) end
|
|
end)
|
|
|
|
Prat.RegisterChatCommand("pratdebug", function(name)
|
|
local dm = addon:GetModule("DebugModules", true)
|
|
if dm then
|
|
dm:ShowCopyDialog()
|
|
end
|
|
end)
|
|
|