load LibWho-2.0, ClassCache & update Chat

update Chat
This commit is contained in:
Crum
2018-01-22 01:30:58 -06:00
parent dabfbfc067
commit a1b896f247
21 changed files with 1765 additions and 151 deletions
+463
View File
@@ -0,0 +1,463 @@
local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local CC = E:NewModule("ClassCache", "AceEvent-3.0");
local LW = LibStub:GetLibrary("LibWho-2.0");
--Cache global variables
--Lua functions
local split, upper = string.split, string.upper
local wipe = table.wipe
local pairs = pairs
local select = select
--WoW API / Variables
local GetBattlefieldScore = GetBattlefieldScore
local GetFriendInfo = GetFriendInfo
local GetGuildRosterInfo = GetGuildRosterInfo
local GetNumBattlefieldScores = GetNumBattlefieldScores
local GetNumFriends = GetNumFriends
local GetNumGuildMembers = GetNumGuildMembers
local GetNumPartyMembers = GetNumPartyMembers
local GetNumRaidMembers = GetNumRaidMembers
local GetTime = GetTime
local IsInGuild = IsInGuild
local UnitClass = UnitClass
local UnitExists = UnitExists
local UnitIsPlayer = UnitIsPlayer
local UnitName = UnitName
local UNKNOWN = UNKNOWN
local GAME_LOCALE = GetLocale()
local ENGLISH_CLASS_NAMES
local function GetEnglishClassName(class)
if class == UNKNOWN then
return class
elseif GAME_LOCALE == "enUS" then
return upper(class)
end
if not ENGLISH_CLASS_NAMES then
ENGLISH_CLASS_NAMES = {}
for english, localized in pairs(LOCALIZED_CLASS_NAMES_MALE) do
ENGLISH_CLASS_NAMES[localized] = english
end
for english, localized in pairs(LOCALIZED_CLASS_NAMES_FEMALE) do
ENGLISH_CLASS_NAMES[localized] = english
end
end
return ENGLISH_CLASS_NAMES[class]
end
local function WhoCallback(result)
if result then
if result.NoLocaleClass then
CC:CachePlayer(result.Name, result.NoLocaleClass)
CC:SendMessage("ClassCacheQueryResult", result.Name, result.NoLocaleClass)
end
end
end
function CC:GetClassByName(name, realm)
if not name or name == "" then return end
if realm and realm == "" then return end
if E.db.general.classCacheStoreInDB then
if realm then
if self.cache[realm] and self.cache[realm][name] then
return self.cache[realm][name]
else
return
end
else
if self.cache[E.myrealm][name] then
return self.cache[E.myrealm][name]
end
end
else
if realm then
if self.tempCache[realm] and self.tempCache[realm][name] then
return self.tempCache[realm][name]
else
return
end
else
if self.tempCache[E.myrealm][name] then
return self.tempCache[E.myrealm][name]
end
end
end
if E.db.general.classCacheRequestInfo then
local result = LW:UserInfo(name, {
queue = LW.WHOLIB_QUEUE_QUIET,
timeout = 0,
callback = function(result)
WhoCallback(result)
end
})
if result and result.NoLocaleClass then
self:CachePlayer(result.Name, result.NoLocaleClass)
return result.NoLocaleClass
end
end
end
function CC:CachePlayer(name, class, realm)
if not (name and class and class ~= UNKNOWN) then return end
if realm and realm == "" then return end
if E.db.general.classCacheStoreInDB then
if realm and not self.cache[realm] then
self.cache[realm] = {}
end
if realm then
self.cache[realm][name] = class
else
self.cache[E.myrealm][name] = class
end
else
if realm and not self.tempCache[realm] then
self.tempCache[realm] = {}
end
if realm then
self.tempCache[realm][name] = class
else
self.tempCache[E.myrealm][name] = class
end
end
end
function CC:SwitchCacheType(init)
if E.db.general.classCacheStoreInDB then
if not self.cache[E.myrealm] then
self.cache[E.myrealm] = {}
end
if not self.cache[E.myrealm][E.myname] then
self.cache[E.myrealm][E.myname] = E.myclass
end
if not init then
for realm in pairs(self.tempCache) do
if not self.cache[realm] then
self.cache[realm] = {}
end
for name, class in pairs(self.tempCache[realm]) do
self.cache[realm][name] = class
end
end
end
else
if not self.tempCache[E.myrealm] then
self.tempCache[E.myrealm] = {}
end
if not self.tempCache[E.myrealm][E.myname] then
self.tempCache[E.myrealm][E.myname] = E.myclass
end
if not init then
for realm in pairs(self.cache) do
if not self.cache[realm] then
self.tempCache[realm] = {}
end
for name, class in pairs(self.cache[realm]) do
self.tempCache[realm][name] = class
end
end
end
end
end
function CC:GetCacheTable()
if E.db.general.classCacheStoreInDB then
return self.cache
else
return self.tempCache
end
end
function CC:GetCacheSize(global)
if global and not (self.cacheDBCalculationTime + 30 < GetTime()) then
return self.cacheDBSize > 1, self.cacheDBSize
elseif not global and not (self.cacheLocalCalculationTime + 30 < GetTime()) then
return self.cacheLocalSize > 1, self.cacheLocalSize
end
local size = 0
if global then
for realm in pairs(self.cache) do
for name in pairs(self.cache[realm]) do
size = size + 1
end
end
self.cacheDBSize = size
self.cacheDBCalculationTime = GetTime()
else
for realm in pairs(self.tempCache) do
for name in pairs(self.tempCache[realm]) do
size = size + 1
end
end
self.cacheLocalSize = size
self.cacheLocalCalculationTime = GetTime()
end
return size > 1, size
end
function CC:WipeCache(global)
if global then
for realm in pairs(self.cache) do
wipe(realm)
end
wipe(self.cache)
self:SwitchCacheType(true)
self.cacheDBCalculationTime = 0
E:Print(L["Class DB cache wiped."])
else
for realm in pairs(self.tempCache) do
wipe(realm)
end
wipe(self.tempCache)
self:SwitchCacheType(true)
self.cacheLocalCalculationTime = 0
E:Print(L["Class session cache wiped."])
end
end
function CC:PLAYER_ENTERING_WORLD()
local inInstance, instanceType = IsInInstance()
self.inInstance = inInstance
if instanceType == "arena" or instanceType == "pvp" then
self.inBattleground = true
else
self.inBattleground = false
end
if self.inInstance or self.inBattleground then
self.lastNumPlayers = 0
self:UnregisterEvent("PLAYER_TARGET_CHANGED")
self:UnregisterEvent("UPDATE_MOUSEOVER_UNIT")
self:UnregisterEvent("PARTY_MEMBERS_CHANGED")
self:UnregisterEvent("RAID_ROSTER_UPDATE")
self:RegisterEvent("UPDATE_BATTLEFIELD_SCORE")
if self.inBattleground then
self:UPDATE_BATTLEFIELD_SCORE()
end
else
self.lastNumPlayers = 0
self:RegisterEvent("PLAYER_TARGET_CHANGED")
self:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
self:RegisterEvent("PARTY_MEMBERS_CHANGED")
self:RegisterEvent("RAID_ROSTER_UPDATE")
self:UnregisterEvent("UPDATE_BATTLEFIELD_SCORE")
end
self:PLAYER_GUILD_UPDATE()
if not self.initUpdate then
if GetNumRaidMembers() > 0 then
self:RAID_ROSTER_UPDATE()
elseif GetNumPartyMembers() > 0 then
self:PARTY_MEMBERS_CHANGED()
end
self:GUILD_ROSTER_UPDATE(nil, true)
self.initUpdate = true
end
end
function CC:PLAYER_GUILD_UPDATE()
if IsInGuild() then
self:RegisterEvent("GUILD_ROSTER_UPDATE")
else
self:UnregisterEvent("RAID_ROSTER_UPDATE")
end
end
function CC:FRIENDLIST_UPDATE()
local name, class, _
for i = 1, GetNumFriends() do
name, _, class = GetFriendInfo(i)
if class then
self:CachePlayer(name, GetEnglishClassName(class))
end
end
end
function CC:GUILD_ROSTER_UPDATE(_, update)
if not update then return end
local name, class, _
for i = 1, GetNumGuildMembers() do
name, _, _, _, _, _, _, _, _, _, class = GetGuildRosterInfo(i)
if class then
self:CachePlayer(name, class)
end
end
end
function CC:PARTY_MEMBERS_CHANGED()
local name, realm, class, _
for i = 1, GetNumPartyMembers() do
name, realm = UnitName("party"..i)
_, class = UnitClass("party"..i)
if not class then return end
if self.inBattleground then
self:CachePlayer(name, class, realm)
else
self:CachePlayer(name, class)
end
end
end
function CC:RAID_ROSTER_UPDATE()
local name, realm, class, _
for i = 1, GetNumRaidMembers() do
name, realm = UnitName("raid"..i)
_, class = UnitClass("raid"..i)
if not class then return end
if self.inBattleground then
self:CachePlayer(name, class, realm)
else
self:CachePlayer(name, class)
end
end
end
function CC:PLAYER_TARGET_CHANGED()
if not UnitExists("target") or not UnitIsPlayer("target") then return end
local _, class = UnitClass("target")
if not class then return end
local name, realm = UnitName("target")
if self.inBattleground then
self:CachePlayer(name, class, realm)
else
self:CachePlayer(name, class)
end
end
function CC:UPDATE_MOUSEOVER_UNIT()
if not UnitExists("mouseover") or not UnitIsPlayer("mouseover") then return end
local _, class = UnitClass("mouseover")
if not class then return end
local name, realm = UnitName("mouseover")
if self.inBattleground then
self:CachePlayer(name, class, realm)
else
self:CachePlayer(name, class)
end
end
function CC:UPDATE_BATTLEFIELD_SCORE()
local numPlayers = GetNumBattlefieldScores() or 0
if self.lastNumPlayers == numPlayers then
return
elseif self.lastNumPlayers > numPlayers then
self.lastNumPlayers = numPlayers
return
end
local name, realm, class, _
for i = 1, numPlayers do
name, _, _, _, _, _, _, _, _, class = GetBattlefieldScore(i)
if name and class then
name, realm = split("-", name)
self:CachePlayer(name, class, realm)
end
end
end
function CC:WHOLIB_QUERY_RESULT(_, query, results, complete)
for _, result in pairs(results) do
if result and result.NoLocaleClass then
self:CachePlayer(result.Name, result.NoLocaleClass)
end
end
end
function CC:ToggleModule()
if E.private.general.classCache then
if not self.initialized then
self:SwitchCacheType(true)
self.initialized = true
end
self:RegisterEvent("PLAYER_ENTERING_WORLD")
self:RegisterEvent("PLAYER_GUILD_UPDATE")
self:RegisterEvent("FRIENDLIST_UPDATE")
self:RegisterEvent("PARTY_MEMBERS_CHANGED")
self:RegisterEvent("RAID_ROSTER_UPDATE")
LW.RegisterCallback(self, "WHOLIB_QUERY_RESULT", "WHOLIB_QUERY_RESULT")
else
self:UnregisterAllEvents()
LW.UnregisterAllCallbacks(self)
end
end
function CC:Initialize()
self.cache = E.global.classCache
self.tempCache = {}
self.cacheLocalCalculationTime = 0
self.cacheDBCalculationTime = 0
LW:SetWhoLibDebug(false)
if E.private.general.classCache then
self:ToggleModule()
end
end
local function InitializeCallback()
CC:Initialize()
end
E:RegisterModule(CC:GetName(), InitializeCallback)
+1
View File
@@ -14,4 +14,5 @@
<Script file="dropdown.lua"/>
<Script file="Cooldowns.lua"/>
<Script file="pluginInstaller.lua"/>
<Script file="ClassCache.lua"/>
</Ui>
@@ -0,0 +1,939 @@
---
--- check for an already loaded old WhoLib
---
if WhoLibByALeX or WhoLib then
-- the WhoLib-1.0 (WhoLibByALeX) or WhoLib (by Malex) is loaded -> fail!
error("an other WhoLib is already running - disable them first!\n")
return
end -- if
---
--- check version
---
assert(LibStub, "LibWho-2.0 requires LibStub")
local major_version = 'LibWho-2.0'
local minor_version = tonumber("154") or 99999
local lib = LibStub:NewLibrary(major_version, minor_version)
if not lib then
return -- already loaded and no upgrade necessary
end
lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib)
local callbacks = lib.callbacks
local am = {}
local om = getmetatable(lib)
if om then
for k, v in pairs(om) do am[k] = v end
end
am.__tostring = function() return major_version end
setmetatable(lib, am)
local function dbgfunc(...) if lib.Debug then print(unpack(arg)) end end
local function NOP() return end
local dbg = NOP
---
--- initalize base
---
if type(lib['hooked']) ~= 'table' then
lib['hooked'] = {}
end -- if
if type(lib['hook']) ~= 'table' then
lib['hook'] = {}
end -- if
if type(lib['events']) ~= 'table' then
lib['events'] = {}
end -- if
if type(lib['embeds']) ~= 'table' then
lib['embeds'] = {}
end -- if
if type(lib['frame']) ~= 'table' then
lib['frame'] = CreateFrame('Frame', major_version);
end -- if
lib['frame']:Hide()
lib.Queue = {[1]={}, [2]={}, [3]={}}
lib.WhoInProgress = false
lib.Result = nil
lib.Args = nil
lib.Total = nil
lib.Quiet = nil
lib.Debug = false
lib.Cache = {}
lib.CacheQueue = {}
lib.SetWhoToUIState = false
lib.MinInterval = 2.5
lib.MaxInterval = 10
---
--- locale
---
if (GetLocale() == "ruRU") then
lib.L = {
['console_queued'] = 'Добавлено в очередь "/who %s"',
['console_query'] = 'Результат "/who %s"',
['gui_wait'] = '- Пожалуйста подождите -',
}
else
-- enUS is the default
lib.L = {
['console_queued'] = 'Added "/who %s" to queue',
['console_query'] = 'Result of "/who %s"',
['gui_wait'] = '- Please Wait -',
}
end -- if
---
--- external functions/constants
---
lib['external'] = {
'WHOLIB_QUEUE_USER',
'WHOLIB_QUEUE_QUIET',
'WHOLIB_QUEUE_SCANNING',
'WHOLIB_FLAG_ALWAYS_CALLBACK',
'Who',
'UserInfo',
'CachedUserInfo',
'GetWhoLibDebug',
'SetWhoLibDebug',
-- 'RegisterWhoLibEvent',
}
-- queues
lib['WHOLIB_QUEUE_USER'] = 1
lib['WHOLIB_QUEUE_QUIET'] = 2
lib['WHOLIB_QUEUE_SCANNING'] = 3
local queue_all = {
[1] = 'WHOLIB_QUEUE_USER',
[2] = 'WHOLIB_QUEUE_QUIET',
[3] = 'WHOLIB_QUEUE_SCANNING',
}
local queue_quiet = {
[2] = 'WHOLIB_QUEUE_QUIET',
[3] = 'WHOLIB_QUEUE_SCANNING',
}
-- bit masks!
lib['WHOLIB_FLAG_ALWAYS_CALLBACK'] = 1
function lib:Reset()
self.Queue = {[1]={}, [2]={}, [3]={}}
self.Cache = {}
self.CacheQueue = {}
end
function lib.Who(defhandler, query, opts)
local self, args, usage = lib, {}, 'Who(query, [opts])'
args.query = self:CheckArgument(usage, 'query', 'string', query)
opts = self:CheckArgument(usage, 'opts', 'table', opts, {})
args.queue = self:CheckPreset(usage, 'opts.queue', queue_all, opts.queue, self.WHOLIB_QUEUE_SCANNING)
args.flags = self:CheckArgument(usage, 'opts.flags', 'number', opts.flags, 0)
args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler)
-- now args - copied and verified from opts
if args.queue == self.WHOLIB_QUEUE_USER then
if WhoFrame:IsShown() then
self:GuiWho(args.query)
else
self:ConsoleWho(args.query)
end
else
self:AskWho(args)
end
end
function lib.UserInfo(defhandler, name, opts)
local self, args, usage = lib, {}, 'UserInfo(name, [opts])'
local now = time()
name = self:CheckArgument(usage, 'name', 'string', name)
if strlen(name) == 0 then return end
if string.find(name, "%-") then --[[dbg("ignoring xrealm: "..name)]] return end
args.name = self:CapitalizeInitial(name)
opts = self:CheckArgument(usage, 'opts', 'table', opts, {})
args.queue = self:CheckPreset(usage, 'opts.queue', queue_quiet, opts.queue, self.WHOLIB_QUEUE_SCANNING)
args.flags = self:CheckArgument(usage, 'opts.flags', 'number', opts.flags, 0)
args.timeout = self:CheckArgument(usage, 'opts.timeout', 'number', opts.timeout, 5)
args.callback, args.handler = self:CheckCallback(usage, 'opts.', opts.callback, opts.handler, defhandler)
-- now args - copied and verified from opts
local cachedName = self.Cache[args.name]
if(cachedName ~= nil)then
-- user is in cache
if(cachedName.valid == true and (args.timeout < 0 or cachedName.last + args.timeout*60 > now))then
-- cache is valid and timeout is in range
--dbg('Info(' .. args.name ..') returned immedeatly')
if(bit.band(args.flags, self.WHOLIB_FLAG_ALWAYS_CALLBACK) ~= 0)then
self:RaiseCallback(args, cachedName.data)
return false
else
return self:DupAll(self:ReturnUserInfo(args.name))
end
elseif(cachedName.valid == false)then
-- query is already running (first try)
if(args.callback ~= nil)then
tinsert(cachedName.callback, args)
end
--dbg('Info(' .. args.name ..') returned cause it\'s already searching')
return nil
end
else
self.Cache[args.name] = {valid=false, inqueue=false, callback={}, data={Name = args.name}, last=now }
end
local cachedName = self.Cache[args.name]
if(cachedName.inqueue)then
-- query is running!
if(args.callback ~= nil)then
tinsert(cachedName.callback, args)
end
dbg('Info(' .. args.name ..') returned cause it\'s already searching')
return nil
end
if (GetLocale() == "ruRU") then -- in ruRU with n- not show information about player in WIM addon
if args.name and strlen(args.name) > 0 then
local query = 'и-"' .. args.name .. '"'
cachedName.inqueue = true
if(args.callback ~= nil)then
tinsert(cachedName.callback, args)
end
self.CacheQueue[query] = args.name
dbg('Info(' .. args.name ..') added to queue')
self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } )
end
else
if args.name and strlen(args.name) > 0 then
local query = 'n-"' .. args.name .. '"'
cachedName.inqueue = true
if(args.callback ~= nil)then
tinsert(cachedName.callback, args)
end
self.CacheQueue[query] = args.name
dbg('Info(' .. args.name ..') added to queue')
self:AskWho( { query = query, queue = args.queue, flags = 0, info = args.name } )
end
end
return nil
end
function lib.CachedUserInfo(_, name)
local self, usage = lib, 'CachedUserInfo(name)'
name = self:CapitalizeInitial(self:CheckArgument(usage, 'name', 'string', name))
if self.Cache[name] == nil then
return nil
else
return self:DupAll(self:ReturnUserInfo(name))
end
end
function lib.GetWhoLibDebug(_, mode)
return lib.Debug
end
function lib.SetWhoLibDebug(_, mode)
lib.Debug = mode
dbg = mode and dbgfunc or NOP
end
--function lib.RegisterWhoLibEvent(defhandler, event, callback, handler)
-- local self, usage = lib, 'RegisterWhoLibEvent(event, callback, [handler])'
--
-- self:CheckPreset(usage, 'event', self.events, event)
-- local callback, handler = self:CheckCallback(usage, '', callback, handler, defhandler, true)
-- table.insert(self.events[event], {callback=callback, handler=handler})
--end
-- non-embedded externals
function lib.Embed(_, handler)
local self, usage = lib, 'Embed(handler)'
self:CheckArgument(usage, 'handler', 'table', handler)
for _,name in pairs(self.external) do
handler[name] = self[name]
end -- do
self['embeds'][handler] = true
return handler
end
function lib.Library(_)
local self = lib
return self:Embed({})
end
---
--- internal functions
---
function lib:AllQueuesEmpty()
local queueCount = getn(self.Queue[1]) + getn(self.Queue[2]) + getn(self.Queue[3]) + getn(self.CacheQueue)
-- Be sure that we have cleared the in-progress status
if self.WhoInProgress then
queueCount = queueCount + 1
end
return queueCount == 0
end
local queryInterval = 5
function lib:GetQueryInterval() return queryInterval end
function lib:AskWhoNextIn5sec()
if self.frame:IsShown() then return end
dbg("Waiting to send next who")
self.Timeout_time = queryInterval
self['frame']:Show()
end
function lib:CancelPendingWhoNext()
lib['frame']:Hide()
end
lib['frame']:SetScript("OnUpdate", function()
lib.Timeout_time = lib.Timeout_time - arg1
if lib.Timeout_time <= 0 then
lib['frame']:Hide()
lib:AskWhoNext()
end -- if
end);
-- queue scheduler
local queue_weights = { [1] = 0.6, [2] = 0.2, [3] = 0.2 }
local queue_bounds = { [1] = 0.6, [2] = 0.2, [3] = 0.2 }
-- allow for single queries from the user to get processed faster
local lastInstantQuery = time()
local INSTANT_QUERY_MIN_INTERVAL = 60 -- only once every 1 min
function lib:UpdateWeights()
local weightsum, sum, count = 0, 0, 0
for k,v in pairs(queue_weights) do
sum = sum + v
weightsum = weightsum + v * getn(self.Queue[k])
end
if weightsum == 0 then
for k,v in pairs(queue_weights) do queue_bounds[k] = v end
return
end
local adjust = sum / weightsum
for k,v in pairs(queue_bounds) do
queue_bounds[k] = queue_weights[k] * adjust * getn(self.Queue[k])
end
end
function lib:GetNextFromScheduler()
self:UpdateWeights()
-- Since an addon could just fill up the user q for instant processing
-- we have to limit instants to 1 per INSTANT_QUERY_MIN_INTERVAL
-- and only try instant fulfilment if it will empty the user queue
if getn(self.Queue[1]) == 1 then
if time() - lastInstantQuery > INSTANT_QUERY_MIN_INTERVAL then
dbg("INSTANT")
lastInstantQuery = time()
return 1, self.Queue[1]
end
end
local n,i = math.random(),0
repeat
i=i+1
n = n - queue_bounds[i]
until i >= getn(self.Queue) or n <= 0
dbg(string.format("Q=%d, bound=%d", i, queue_bounds[i]))
if getn(self.Queue[i]) > 0 then
dbg(string.format("Q=%d, bound=%d", i, queue_bounds[i]))
return i, self.Queue[i]
else
dbg("Queues empty, waiting")
end
end
lib.queue_bounds = queue_bounds
function lib:AskWhoNext()
if lib.frame:IsShown() then
dbg("Already waiting")
return
end
self:CancelPendingWhoNext()
if self.WhoInProgress then
-- if we had a who going, it didnt complete
dbg("TIMEOUT: "..self.Args.query)
local args = self.Args
self.Args = nil
-- if args.info and self.CacheQueue[args.query] ~= nil then
dbg("Requeing "..args.query)
tinsert(self.Queue[args.queue], args)
if args.console_show ~= nil then
DEFAULT_CHAT_FRAME:AddMessage(string.format("Timeout on result of '%s' - retrying...", args.query), 1, 1, 0)
args.console_show = true
end
-- end
if queryInterval < lib.MaxInterval then
queryInterval = queryInterval + 0.5
dbg("--Throttling down to 1 who per " .. queryInterval .. "s")
end
end
self.WhoInProgress = false
local v,k,args = nil
local kludge = 10
repeat
k, v = self:GetNextFromScheduler()
if not k then break end
if WhoFrame:IsShown() and k > self.WHOLIB_QUEUE_QUIET then
break
end
if getn(v) > 0 then
args = tremove(v, 1)
break
end
kludge = kludge - 1
until kludge <= 0
if args then
self.WhoInProgress = true
self.Result = {}
self.Args = args
self.Total = -1
if(args.console_show == true)then
DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_query'], args.query), 1, 1, 0)
end
if args.queue == self.WHOLIB_QUEUE_USER then
WhoFrameEditBox:SetText(args.query)
self.Quiet = false
if args.whotoui then
self.hooked.SetWhoToUI(args.whotoui)
else
self.hooked.SetWhoToUI(args.gui and true or false)
end
else
-- self.hooked.SetWhoToUI(true)
self.Quiet = true
end
dbg("QUERY: "..args.query)
-- self.hooked.SendWho(args.query)
else
self.Args = nil
self.WhoInProgress = false
end
-- Keep processing the who queue if there is more work
if not self:AllQueuesEmpty() then
self:AskWhoNextIn5sec()
else
dbg("*** Done processing requests ***")
end
end
function lib:AskWho(args)
tinsert(self.Queue[args.queue], args)
dbg('[' .. args.queue .. '] added "' .. args.query .. '", queues=' .. getn(self.Queue[1]) .. '/'.. getn(self.Queue[2]) .. '/'.. getn(self.Queue[3]))
self:TriggerEvent('WHOLIB_QUERY_ADDED')
self:AskWhoNext()
end
function lib:ReturnWho()
if not self.Args then
self.Quiet = nil
return
end
if(self.Args.queue == self.WHOLIB_QUEUE_QUIET or self.Args.queue == self.WHOLIB_QUEUE_SCANNING)then
self.Quiet = nil
end
if queryInterval > self.MinInterval then
queryInterval = queryInterval - 0.5
dbg("--Throttling up to 1 who per " .. queryInterval .. "s")
end
self.WhoInProgress = false
dbg("RESULT: "..self.Args.query)
dbg('[' .. self.Args.queue .. '] returned "' .. self.Args.query .. '", total=' .. self.Total ..' , queues=' .. getn(self.Queue[1]) .. '/'.. getn(self.Queue[2]) .. '/'.. getn(self.Queue[3]))
local now = time()
local complete = (self.Total == getn(self.Result)) and (self.Total < MAX_WHOS_FROM_SERVER)
for _,v in pairs(self.Result)do
if v.Name then
if(self.Cache[v.Name] == nil)then
self.Cache[v.Name] = { inqueue = false, callback = {} }
end
local cachedName = self.Cache[v.Name]
cachedName.valid = true -- is now valid
cachedName.data = v -- update data
cachedName.data.Online = true -- player is online
cachedName.last = now -- update timestamp
if(cachedName.inqueue)then
if(self.Args.info and self.CacheQueue[self.Args.query] == v.Name)then
-- found by the query which was created to -> remove us from query
self.CacheQueue[self.Args.query] = nil
else
-- found by another query
for k2,v2 in pairs(self.CacheQueue) do
if(v2 == v.Name)then
for i=self.WHOLIB_QUEUE_QUIET, self.WHOLIB_QUEUE_SCANNING do
for k3,v3 in pairs(self.Queue[i]) do
if(v3.query == k2 and v3.info)then
-- remove the query which was generated for this user, cause another query was faster...
dbg("Found '"..v.Name.."' early via query '"..self.Args.query.."'")
table.remove(self.Queue[i], k3)
self.CacheQueue[k2] = nil
end
end
end
end
end
end
dbg('Info(' .. v.Name ..') returned: on')
for _,v2 in pairs(cachedName.callback) do
self:RaiseCallback(v2, self:ReturnUserInfo(v.Name))
end
cachedName.callback = {}
end
cachedName.inqueue = false -- query is done
end
end
if(self.Args.info and self.CacheQueue[self.Args.query])then
-- the query did not deliver the result => not online!
local name = self.CacheQueue[self.Args.query]
local cachedName = self.Cache[name]
if (cachedName.inqueue)then
-- nothing found (yet)
cachedName.valid = true -- is now valid
cachedName.inqueue = false -- query is done?
cachedName.last = now -- update timestamp
if(complete)then
cachedName.data.Online = false -- player is offline
else
cachedName.data.Online = nil -- player is unknown (more results from who than can be displayed)
end
end
dbg('Info(' .. name ..') returned: ' .. (cachedName.data.Online == false and 'off' or 'unkn'))
for _,v in pairs(cachedName.callback) do
self:RaiseCallback(v, self:ReturnUserInfo(name))
end
cachedName.callback = {}
self.CacheQueue[self.Args.query] = nil
end
self:RaiseCallback(self.Args, self.Args.query, self.Result, complete, self.Args.info)
self:TriggerEvent('WHOLIB_QUERY_RESULT', self.Args.query, self.Result, complete, self.Args.info)
if not self:AllQueuesEmpty() then
self:AskWhoNextIn5sec()
end
end
function lib:GuiWho(msg)
if(msg == self.L['gui_wait'])then
return
end
for _,v in pairs(self.Queue[self.WHOLIB_QUEUE_USER]) do
if(v.gui == true)then
return
end
end
if(self.WhoInProgress)then
WhoFrameEditBox:SetText(self.L['gui_wait'])
end
self.savedText = msg
self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, gui = true})
WhoFrameEditBox:ClearFocus();
end
function lib:ConsoleWho(msg)
--WhoFrameEditBox:SetText(msg)
local console_show = false
local q1 = self.Queue[self.WHOLIB_QUEUE_USER]
local q1count = getn(q1)
if(q1count > 0 and q1[q1count].query == msg)then -- last query is itdenical: drop
return
end
if(q1count > 0 and q1[q1count].console_show == false)then -- display 'queued' if console and not yet shown
DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], q1[q1count].query), 1, 1, 0)
q1[q1count].console_show = true
end
if(q1count > 0 or self.WhoInProgress)then
DEFAULT_CHAT_FRAME:AddMessage(string.format(self.L['console_queued'], msg), 1, 1, 0)
console_show = true
end
self:AskWho({query = msg, queue = self.WHOLIB_QUEUE_USER, flags = 0, console_show = console_show})
end
function lib:ReturnUserInfo(name)
if(name ~= nil and self ~= nil and self.Cache ~= nil and self.Cache[name] ~= nil) then
return self.Cache[name].data, (time() - self.Cache[name].last) / 60
end
end
function lib:RaiseCallback(args, ...)
if type(args.callback) == 'function' then
args.callback(self:DupAll(unpack(args)))
elseif args.callback then -- must be a string
args.handler[args.callback](args.handler, self:DupAll(unpack(args)))
end -- if
end
-- Argument checking
function lib:CheckArgument(func, name, argtype, arg, defarg)
if arg == nil and defarg ~= nil then
return defarg
elseif type(arg) == argtype then
return arg
else
error(string.format("%s: '%s' - %s%s expected got %s", func, name, (defarg ~= nil) and 'nil or ' or '', argtype, type(arg)), 3)
end -- if
end
function lib:CheckPreset(func, name, preset, arg, defarg)
if arg == nil and defarg ~= nil then
return defarg
elseif arg ~= nil and preset[arg] ~= nil then
return arg
else
local p = {}
for k,v in pairs(preset) do
if type(v) ~= 'string' then
table.insert(p, k)
else
table.insert(p, v)
end -- if
end -- for
error(string.format("%s: '%s' - one of %s%s expected got %s", func, name, (defarg ~= nil) and 'nil, ' or '', table.concat(p, ', '), self:simple_dump(arg)), 3)
end -- if
end
function lib:CheckCallback(func, prefix, callback, handler, defhandler, nonil)
if not nonil and callback == nil then
-- no callback: ignore handler
return nil, nil
elseif type(callback) == 'function' then
-- simple function
if handler ~= nil then
error(string.format("%s: '%shandler' - nil expected got %s", func, prefix, type(arg)), 3)
end -- if
elseif type(callback) == 'string' then
-- method
if handler == nil then
handler = defhandler
end -- if
if type(handler) ~= 'table' or type(handler[callback]) ~= 'function' or handler == self then
error(string.format("%s: '%shandler' - nil or function expected got %s", func, prefix, type(arg)), 3)
end -- if
else
error(string.format("%s: '%scallback' - %sfunction or string expected got %s", func, prefix, nonil and 'nil or ' or '', type(arg)), 3)
end -- if
return callback, handler
end
-- helpers
function lib:simple_dump(x)
if type(x) == 'string' then
return 'string \''..x..'\''
elseif type(x) == 'number' then
return 'number '..x
else
return type(x)
end
end
function lib:Dup(from)
local to = {}
for k,v in pairs(from) do
if type(v) == 'table' then
to[k] = self:Dup(v)
else
to[k] = v
end -- if
end -- for
return to
end
function lib:DupAll(x, ...)
if type(x) == 'table' then
return self:Dup(x), self:DupAll(unpack(args))
elseif x ~= nil then
return x, self:DupAll(unpack(args))
else
return nil
end -- if
end
local MULTIBYTE_FIRST_CHAR = "^([\192-\255]?%a?[\128-\191]*)"
function lib:CapitalizeInitial(name)
return string.gsub(name, MULTIBYTE_FIRST_CHAR, string.upper, 1)
end
---
--- user events (Using CallbackHandler)
---
lib.PossibleEvents = {
'WHOLIB_QUERY_RESULT',
'WHOLIB_QUERY_ADDED',
}
function lib:TriggerEvent(...)
callbacks:Fire(event, unpack(arg))
end
---
--- slash commands
---
SlashCmdList['WHO'] = function(msg)
dbg("console /who: "..msg)
-- new /who function
--local self = lib
if(msg == '')then
lib:GuiWho(WhoFrame_GetDefaultWhoCommand())
elseif(WhoFrame:IsVisible())then
lib:GuiWho(msg)
else
lib:ConsoleWho(msg)
end
end
SlashCmdList['WHOLIB_DEBUG'] = function()
-- /wholibdebug: toggle debug on/off
local self = lib
self:SetWhoLibDebug(not self.Debug)
end
SLASH_WHOLIB_DEBUG1 = '/wholibdebug'
---
--- hook activation
---
-- functions to hook
local hooks = {
-- 'SendWho',
-- 'WhoFrameEditBox_OnEnterPressed',
-- 'FriendsFrame_OnEvent',
-- 'SetWhoToUI',
}
-- hook all functions (which are not yet hooked)
for _, name in pairs(hooks) do
if not lib['hooked'][name] then
lib['hooked'][name] = _G[name]
_G[name] = function(...)
lib.hook[name](lib, unpack(arg))
end -- function
end -- if
end -- for
-- fake 'WhoFrame:Hide' as hooked
table.insert(hooks, 'WhoFrame_Hide')
-- check for unused hooks -> remove function
for name, _ in pairs(lib['hook']) do
if not hooks[name] then
lib['hook'][name] = function() end
end -- if
end -- for
-- secure hook 'WhoFrame:Hide'
if not lib['hooked']['WhoFrame_Hide'] then
lib['hooked']['WhoFrame_Hide'] = true
hooksecurefunc(WhoFrame, 'Hide', function(...)
lib['hook']['WhoFrame_Hide'](lib, unpack(arg))
end -- function
)
end -- if
----- Coroutine based implementation (future)
--function lib:sendWhoResult(val)
-- coroutine.yield(val)
--end
--
--function lib:sendWaitState(val)
-- coroutine.yield(val)
--end
--
--function lib:producer()
-- return coroutine.create(
-- function()
-- lib:AskWhoNext()
-- lib:sendWaitState(true)
--
-- -- Resumed look for data
--
-- end)
--end
---
--- hook replacements
---
function lib.hook.SendWho(self, msg)
dbg("SendWho: "..msg)
lib.AskWho(self, {query = msg, queue = lib.WHOLIB_QUEUE_USER, whotoui = lib.SetWhoToUIState, flags = 0})
end
function lib.hook.WhoFrameEditBox_OnEnterPressed(self)
lib:GuiWho(WhoFrameEditBox:GetText())
end
--[[
function lib.hook.FriendsFrame_OnEvent(self, ...)
if event ~= 'WHO_LIST_UPDATE' or not lib.Quiet then
lib.hooked.FriendsFrame_OnEvent(...)
end
end
]]
hooksecurefunc(FriendsFrame, 'RegisterEvent', function(self, event)
if(event == "WHO_LIST_UPDATE") then
self:UnregisterEvent("WHO_LIST_UPDATE");
end
end);
function lib.hook.SetWhoToUI(self, state)
lib.SetWhoToUIState = state
end
function lib.hook.WhoFrame_Hide(self)
if(not lib.WhoInProgress)then
lib:AskWhoNextIn5sec()
end
end
---
--- WoW events
---
local who_pattern = string.gsub(WHO_NUM_RESULTS, '%%d', '%%d%+')
function lib:CHAT_MSG_SYSTEM(arg1)
if arg1 and string.find(arg1, who_pattern) then
lib:ProcessWhoResults()
end
end
FriendsFrame:UnregisterEvent("WHO_LIST_UPDATE")
function lib:WHO_LIST_UPDATE()
if not lib.Quiet then
WhoList_Update()
FriendsFrame_Update()
end
lib:ProcessWhoResults()
end
function lib:ProcessWhoResults()
self.Result = self.Result and table.wipe(self.Result) or {}
local num
self.Total, num = GetNumWhoResults()
for i=1, num do
local charname, guildname, level, race, class, zone, nonlocalclass, sex = GetWhoInfo(i)
self.Result[i] = {Name=charname, Guild=guildname, Level=level, Race=race, Class=class, Zone=zone, NoLocaleClass=nonlocalclass, Sex=sex }
end
self:ReturnWho()
end
---
--- event activation
---
lib['frame']:UnregisterAllEvents();
lib['frame']:SetScript("OnEvent", function(...)
lib[event](lib, unpack(arg))
end);
for _,name in pairs({
'CHAT_MSG_SYSTEM',
'WHO_LIST_UPDATE',
}) do
lib['frame']:RegisterEvent(name);
end -- for
---
--- re-embed
---
for target,_ in pairs(lib['embeds']) do
if type(target) == 'table' then
lib:Embed(target)
end -- if
end -- for
@@ -0,0 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="LibWho-2.0.lua"/>
</Ui>
@@ -20,6 +20,7 @@
<Include file="LibCompress\LibCompress.xml"/>
<Include file="LibBase64-1.0\LibBase64-1.0.xml"/>
<Include file="LibAnim\LibAnim.xml"/>
<Include file="LibWho-2.0\LibWho-2.0.xml"/>
<Include file="LibUIDropDownMenu\LibUIDropDownMenu.xml"/>
<Include file="LibItemSearch-1.2\LibItemSearch-1.2.xml"/>
</Ui>
+167 -128
View File
@@ -1,6 +1,6 @@
local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local CH = E:NewModule("Chat", "AceTimer-3.0", "AceHook-3.0", "AceEvent-3.0");
--local CC = E:GetModule("ClassCache")
local CC = E:GetModule("ClassCache");
local LSM = LibStub("LibSharedMedia-3.0");
--Cache global variables
@@ -212,6 +212,45 @@ local function ChatFrame_OnMouseScroll(frame, delta)
end
end
local function ChatFrame_AddMessageEventFilter(event, filter)
assert(event and filter)
if chatFilters[event] then
-- Only allow a filter to be added once
for index, filterFunc in next, chatFilters[event] do
if filterFunc == filter then
return
end
end
else
chatFilters[event] = {}
end
tinsert(chatFilters[event], filter)
end
local function ChatFrame_RemoveMessageEventFilter(event, filter)
assert(event and filter)
if chatFilters[event] then
for index, filterFunc in next, chatFilters[event] do
if filterFunc == filter then
tremove(chatFilters[event], index)
end
end
if getn(chatFilters[event]) == 0 then
chatFilters[event] = nil
end
end
end
local function ChatFrame_GetMessageEventFilters(event)
assert(event)
return chatFilters[event]
end
function CH:GetGroupDistribution()
local inInstance, kind = IsInInstance()
if inInstance and kind == "pvp" then
@@ -228,7 +267,7 @@ end
function CH:InsertEmotions(msg)
for k,v in pairs(smileyKeys) do
msg = gsub(msg,k,"|T"..smileyPack[v]..":16|t")
-- msg = gsub(msg,k,"|T"..smileyPack[v]..":16|t")
end
return msg
end
@@ -362,7 +401,7 @@ end
local function removeIconFromLine(text)
text = gsub(text, "|TInterface\\TargetingFrame\\UI%-RaidTargetingIcon_(%d+):0|t", function(x)
x = _G["RAID_TARGET_"..x];return "{"..strlower(x).."}"
x = _G["RAID_TARGET_"..x]; return "{"..strlower(x).."}"
end)
text = gsub(text, "|H.-|h(.-)|h", "%1")
@@ -712,8 +751,8 @@ function CH:OnHyperlinkLeave()
end
end
function CH:OnMessageScrollChanged(frame)
if hyperLinkEntered == frame then
function CH:OnMessageScrollChanged()
if hyperLinkEntered == this then
HideUIPanel(GameTooltip)
hyperLinkEntered = false
end
@@ -750,7 +789,7 @@ function CH.ShortChannel()
end
function CH:ConcatenateTimeStamp(msg)
if (CH.db.timeStampFormat and CH.db.timeStampFormat ~= "NONE" ) then
if CH.db.timeStampFormat and CH.db.timeStampFormat ~= "NONE" then
local timeStamp = BetterDate(CH.db.timeStampFormat, CH.timeOverride or time())
timeStamp = gsub(timeStamp, " ", "")
timeStamp = gsub(timeStamp, "AM", " AM")
@@ -773,7 +812,7 @@ function GetColoredName(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, a
if arg2 and arg2 ~= "" then
local name, realm = strsplit("-", arg2)
--local englishClass = CC:GetClassByName(name, realm)
local englishClass = CC:GetClassByName(name, realm)
if englishClass then
local classColorTable = CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS[englishClass] or RAID_CLASS_COLORS[englishClass]
@@ -802,112 +841,112 @@ end
function CH:ChatFrame_MessageEventHandler(event, ...)
if event == "UPDATE_CHAT_WINDOWS" then
local name, fontSize, r, g, b, a, shown, locked = GetChatWindowInfo(self:GetID());
if ( fontSize > 0 ) then
local fontFile, unused, fontFlags = self:GetFont();
self:SetFont(fontFile, fontSize, fontFlags);
local name, fontSize, r, g, b, a, shown, locked = GetChatWindowInfo(self:GetID())
if fontSize > 0 then
local fontFile, unused, fontFlags = self:GetFont()
self:SetFont(fontFile, fontSize, fontFlags)
end
if ( shown ) then
self:Show();
if shown then
self:Show()
end
-- Do more stuff!!!
ChatFrame_RegisterForMessages(GetChatWindowMessages(self:GetID()));
ChatFrame_RegisterForChannels(GetChatWindowChannels(self:GetID()));
return;
ChatFrame_RegisterForMessages(GetChatWindowMessages(self:GetID()))
ChatFrame_RegisterForChannels(GetChatWindowChannels(self:GetID()))
return
end
if ( event == "PLAYER_ENTERING_WORLD" ) then
self.defaultLanguage = GetDefaultLanguage();
return;
if event == "PLAYER_ENTERING_WORLD" then
self.defaultLanguage = GetDefaultLanguage()
return
end
if ( event == "TIME_PLAYED_MSG" ) then
ChatFrame_DisplayTimePlayed(arg1, arg2);
return;
if event == "TIME_PLAYED_MSG" then
ChatFrame_DisplayTimePlayed(arg1, arg2)
return
end
if ( event == "PLAYER_LEVEL_UP" ) then
if event == "PLAYER_LEVEL_UP" then
-- Level up
local info = ChatTypeInfo["SYSTEM"];
local info = ChatTypeInfo["SYSTEM"]
local string = format(TEXT(LEVEL_UP), arg1);
self:AddMessage(string, info.r, info.g, info.b, info.id);
local string = format(TEXT(LEVEL_UP), arg1)
self:AddMessage(string, info.r, info.g, info.b, info.id)
if ( arg3 > 0 ) then
string = format(TEXT(LEVEL_UP_HEALTH_MANA), arg2, arg3);
if arg3 > 0 then
string = format(TEXT(LEVEL_UP_HEALTH_MANA), arg2, arg3)
else
string = format(TEXT(LEVEL_UP_HEALTH), arg2);
string = format(TEXT(LEVEL_UP_HEALTH), arg2)
end
self:AddMessage(string, info.r, info.g, info.b, info.id);
self:AddMessage(string, info.r, info.g, info.b, info.id)
if ( arg4 > 0 ) then
string = format(GetText("LEVEL_UP_CHAR_POINTS", nil, arg4), arg4);
self:AddMessage(string, info.r, info.g, info.b, info.id);
if arg4 > 0 then
string = format(GetText("LEVEL_UP_CHAR_POINTS", nil, arg4), arg4)
self:AddMessage(string, info.r, info.g, info.b, info.id)
end
if ( arg5 > 0 ) then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT0_NAME), arg5);
self:AddMessage(string, info.r, info.g, info.b, info.id);
if arg5 > 0 then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT0_NAME), arg5)
self:AddMessage(string, info.r, info.g, info.b, info.id)
end
if ( arg6 > 0 ) then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT1_NAME), arg6);
self:AddMessage(string, info.r, info.g, info.b, info.id);
if arg6 > 0 then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT1_NAME), arg6)
self:AddMessage(string, info.r, info.g, info.b, info.id)
end
if ( arg7 > 0 ) then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT2_NAME), arg7);
self:AddMessage(string, info.r, info.g, info.b, info.id);
if arg7 > 0 then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT2_NAME), arg7)
self:AddMessage(string, info.r, info.g, info.b, info.id)
end
if ( arg8 > 0 ) then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT3_NAME), arg8);
self:AddMessage(string, info.r, info.g, info.b, info.id);
if arg8 > 0 then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT3_NAME), arg8)
self:AddMessage(string, info.r, info.g, info.b, info.id)
end
if ( arg9 > 0 ) then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT4_NAME), arg9);
self:AddMessage(string, info.r, info.g, info.b, info.id);
if arg9 > 0 then
string = format(TEXT(LEVEL_UP_STAT), TEXT(SPELL_STAT4_NAME), arg9)
self:AddMessage(string, info.r, info.g, info.b, info.id)
end
return;
return
end
if ( event == "CHARACTER_POINTS_CHANGED" ) then
local info = ChatTypeInfo["SYSTEM"];
if ( arg2 > 0 ) then
local cp1, cp2 = UnitCharacterPoints("player");
if ( cp2 ) then
local string = format(GetText("LEVEL_UP_SKILL_POINTS", nil, cp2), cp2);
self:AddMessage(string, info.r, info.g, info.b, info.id);
if event == "CHARACTER_POINTS_CHANGED" then
local info = ChatTypeInfo["SYSTEM"]
if arg2 > 0 then
local cp1, cp2 = UnitCharacterPoints("player")
if cp2 then
local string = format(GetText("LEVEL_UP_SKILL_POINTS", nil, cp2), cp2)
self:AddMessage(string, info.r, info.g, info.b, info.id)
end
end
return;
return
end
if ( event == "GUILD_MOTD" ) then
if ( arg1 and (strlen(arg1) > 0) ) then
local info = ChatTypeInfo["GUILD"];
local string = format(TEXT(GUILD_MOTD_TEMPLATE), arg1);
self:AddMessage(string, info.r, info.g, info.b, info.id);
if event == "GUILD_MOTD" then
if arg1 and (strlen(arg1) > 0) then
local info = ChatTypeInfo["GUILD"]
local string = format(TEXT(GUILD_MOTD_TEMPLATE), arg1)
self:AddMessage(string, info.r, info.g, info.b, info.id)
end
return;
return
end
if ( event == "EXECUTE_CHAT_LINE" ) then
self.editBox:SetText(arg1);
ChatEdit_SendText(self.editBox);
ChatEdit_OnEscapePressed(self.editBox);
return;
if event == "EXECUTE_CHAT_LINE" then
self.editBox:SetText(arg1)
ChatEdit_SendText(self.editBox)
ChatEdit_OnEscapePressed(self.editBox)
return
end
if ( event == "UPDATE_CHAT_COLOR" ) then
local info = ChatTypeInfo[strupper(arg1)];
if ( info ) then
info.r = arg2;
info.g = arg3;
info.b = arg4;
self:UpdateColorByID(info.id, info.r, info.g, info.b);
if event == "UPDATE_CHAT_COLOR" then
local info = ChatTypeInfo[strupper(arg1)]
if info then
info.r = arg2
info.g = arg3
info.b = arg4
self:UpdateColorByID(info.id, info.r, info.g, info.b)
if ( strupper(arg1) == "WHISPER" ) then
info = ChatTypeInfo["REPLY"];
if ( info ) then
info.r = arg2;
info.g = arg3;
info.b = arg4;
self:UpdateColorByID(info.id, info.r, info.g, info.b);
if strupper(arg1) == "WHISPER" then
info = ChatTypeInfo["REPLY"]
if info then
info.r = arg2
info.g = arg3
info.b = arg4
self:UpdateColorByID(info.id, info.r, info.g, info.b)
end
end
end
return;
return
end
if strsub(event, 1, 8) == "CHAT_MSG" then
local type = strsub(event, 10)
@@ -954,7 +993,7 @@ function CH:ChatFrame_MessageEventHandler(event, ...)
end
end
end
if (found == 0) or not info then
if found == 0 or not info then
return true
end
end
@@ -1031,15 +1070,15 @@ function CH:ChatFrame_MessageEventHandler(event, ...)
arg1 = gsub(arg1, "%%", "%%%%")
end
local showLink = 1;
if ( strsub(type, 1, 7) == "MONSTER" or type == "RAID_BOSS_EMOTE" ) then
showLink = nil;
local showLink = 1
if strsub(type, 1, 7) == "MONSTER" or type == "RAID_BOSS_EMOTE" then
showLink = nil
else
arg1 = gsub(arg1, "%%", "%%%%");
arg1 = gsub(arg1, "%%", "%%%%")
end
if (strlen(arg3) > 0) and (arg3 ~= "Universal") and (arg3 ~= GetDefaultLanguage()) then
local languageHeader = "["..arg3.."] "
if ( showLink and (strlen(arg2) > 0) ) then
if showLink and (strlen(arg2) > 0) then
body = format(_G["CHAT_"..type.."_GET"]..languageHeader..arg1, pflag.."|Hplayer:"..arg2.."|h".."["..arg2.."]".."|h")
else
body = format(_G["CHAT_"..type.."_GET"]..languageHeader..arg1, pflag..arg2)
@@ -1122,7 +1161,7 @@ local function OnTextChanged(self)
if strsub(text, 1, 4) == "/tt " then
local unitname, realm = UnitName("target")
if unitname and realm then
unitname = unitname .. "-" .. realm:gsub(" ", "")
unitname = unitname .. "-" .. gsub(realm, " ", "")
end
ChatFrame_SendTell((unitname or L["Invalid Target"]), ChatFrame1)
end
@@ -1135,7 +1174,7 @@ local function OnTextChanged(self)
local new, found = gsub(text, "|Kf(%S+)|k(%S+)%s(%S+)|k", "%2 %3")
if found > 0 then
new = new:gsub("|", "")
new = gsub(new, "|", "")
self:SetText(new)
end
end
@@ -1287,8 +1326,8 @@ end
local protectLinks = {}
function CH:CheckKeyword(message)
for itemLink in message:gmatch("|%x+|Hitem:.-|h.-|h|r") do
protectLinks[itemLink] = itemLink:gsub("%s","|s")
for itemLink in gmatch(message, "|%x+|Hitem:.-|h.-|h|r") do
protectLinks[itemLink] = gsub(itemLink, "%s","|s")
for keyword, _ in pairs(CH.Keywords) do
if itemLink == keyword then
if self.db.keywordSound ~= "None" and not self.SoundPlayed then
@@ -1301,17 +1340,17 @@ function CH:CheckKeyword(message)
end
for itemLink, tempLink in pairs(protectLinks) do
message = message:gsub(itemLink:gsub("([%(%)%.%%%+%-%*%?%[%^%$])","%%%1"), tempLink)
message = gsub(message, gsub(itemLink, "([%(%)%.%%%+%-%*%?%[%^%$])","%%%1"), tempLink)
end
local classColorTable, tempWord, rebuiltString, lowerCaseWord, wordMatch, classMatch
local isFirstWord = true
for word in message:gmatch("%s-[^%s]+%s*") do
tempWord = word:gsub("[%s%p]", "")
lowerCaseWord = tempWord:lower()
for word in gmatch(message, "%s-[^%s]+%s*") do
tempWord = gsub(word, "[%s%p]", "")
lowerCaseWord = strlower(tempWord)
for keyword, _ in pairs(CH.Keywords) do
if lowerCaseWord == keyword:lower() then
word = word:gsub(tempWord, format("%s%s|r", E.media.hexvaluecolor, tempWord))
if lowerCaseWord == strlower(keyword) then
word = gsub(word, tempWord, format("%s%s|r", E.media.hexvaluecolor, tempWord))
if self.db.keywordSound ~= "None" and not self.SoundPlayed then
PlaySoundFile(LSM:Fetch("sound", self.db.keywordSound), "Master")
self.SoundPlayed = true
@@ -1321,14 +1360,14 @@ function CH:CheckKeyword(message)
end
if self.db.classColorMentionsChat and E.private.general.classCache then
tempWord = word:gsub("^[%s%p]-([^%s%p]+)([%-]?[^%s%p]-)[%s%p]*$","%1%2")
tempWord = gsub(word, "^[%s%p]-([^%s%p]+)([%-]?[^%s%p]-)[%s%p]*$","%1%2")
--classMatch = CC:GetCacheTable()[E.myrealm][tempWord]
classMatch = CC:GetCacheTable()[E.myrealm][tempWord]
wordMatch = classMatch and lowerCaseWord
if wordMatch and not E.global.chat.classColorMentionExcludedNames[wordMatch] then
classColorTable = CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS[classMatch] or RAID_CLASS_COLORS[classMatch]
word = word:gsub(tempWord:gsub("%-","%%-"), format("\124cff%.2x%.2x%.2x%s\124r", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255, tempWord))
word = gsub(word, gsub(tempWord, "%-","%%-"), format("\124cff%.2x%.2x%.2x%s\124r", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255, tempWord))
end
end
@@ -1341,7 +1380,7 @@ function CH:CheckKeyword(message)
end
for itemLink, tempLink in pairs(protectLinks) do
rebuiltString = rebuiltString:gsub(tempLink:gsub("([%(%)%.%%%+%-%*%?%[%^%$])","%%%1"), itemLink)
rebuiltString = gsub(rebuiltString, gsub(tempLink, "([%(%)%.%%%+%-%*%?%[%^%$])","%%%1"), itemLink)
protectLinks[itemLink] = nil
end
@@ -1652,34 +1691,34 @@ function CH:Initialize()
end
--First get all pre-existing filters and copy them to our version of chatFilters using ChatFrame_GetMessageEventFilters
--for name, _ in pairs(ChatTypeGroup) do
-- for i = 1, getn(ChatTypeGroup[name]) do
-- local filterFuncTable = ChatFrame_GetMessageEventFilters(ChatTypeGroup[name][i])
-- if filterFuncTable then
-- chatFilters[ChatTypeGroup[name][i]] = {}
--
-- for j = 1, getn(filterFuncTable) do
-- local filterFunc = filterFuncTable[j]
-- tinsert(chatFilters[ChatTypeGroup[name][i]], filterFunc)
-- end
-- end
-- end
--end
for name, _ in pairs(ChatTypeGroup) do
for i = 1, getn(ChatTypeGroup[name]) do
local filterFuncTable = ChatFrame_GetMessageEventFilters(ChatTypeGroup[name][i])
if filterFuncTable then
chatFilters[ChatTypeGroup[name][i]] = {}
for j = 1, getn(filterFuncTable) do
local filterFunc = filterFuncTable[j]
tinsert(chatFilters[ChatTypeGroup[name][i]], filterFunc)
end
end
end
end
--CHAT_MSG_CHANNEL isn't located inside ChatTypeGroup
--local filterFuncTable = ChatFrame_GetMessageEventFilters("CHAT_MSG_CHANNEL")
--if filterFuncTable then
-- chatFilters["CHAT_MSG_CHANNEL"] = {}
--
-- for j = 1, getn(filterFuncTable) do
-- local filterFunc = filterFuncTable[j]
-- tinsert(chatFilters["CHAT_MSG_CHANNEL"], filterFunc)
-- end
--end
local filterFuncTable = ChatFrame_GetMessageEventFilters("CHAT_MSG_CHANNEL")
if filterFuncTable then
chatFilters["CHAT_MSG_CHANNEL"] = {}
for j = 1, getn(filterFuncTable) do
local filterFunc = filterFuncTable[j]
tinsert(chatFilters["CHAT_MSG_CHANNEL"], filterFunc)
end
end
--Now hook onto Blizzards functions for other addons
--self:SecureHook("ChatFrame_AddMessageEventFilter")
--self:SecureHook("ChatFrame_RemoveMessageEventFilter")
hooksecurefunc(self, "ChatFrame_AddMessageEventFilter", ChatFrame_AddMessageEventFilter)
hooksecurefunc(self, "ChatFrame_RemoveMessageEventFilter", ChatFrame_RemoveMessageEventFilter)
self:SecureHook("FCF_SetWindowAlpha")
@@ -1700,7 +1739,7 @@ function CH:Initialize()
end
for _, event in pairs(FindURL_Events) do
--ChatFrame_AddMessageEventFilter(event, CH[event] or CH.FindURL)
ChatFrame_AddMessageEventFilter(event, CH[event] or CH.FindURL)
local nType = strsub(event, 10)
if nType ~= "AFK" and nType ~= "DND" then
self:RegisterEvent(event, "SaveChatHistory")
@@ -1,12 +1,12 @@
local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local M = E:GetModule("Misc");
-- local CH = E:GetModule("Chat");
-- local CC = E:GetModule("ClassCache");
local CH = E:GetModule("Chat");
local CC = E:GetModule("ClassCache");
--Cache global variables
--Lua functions
local select, unpack, type = select, unpack, type
local format, gsub = string.format, string.gsub
local format, gsub, match, gmatch = string.format, string.gsub, string.match, string.gmatch
local strlower = strlower
--WoW API / Variables
local CreateFrame = CreateFrame
@@ -29,17 +29,17 @@ function M:UpdateBubbleBorder()
if E.private.chat.enable and E.private.general.classCache and E.private.general.classColorMentionsSpeech then
local classColorTable, isFirstWord, rebuiltString, lowerCaseWord, tempWord, wordMatch, classMatch
local text = this.text:GetText()
if text and text:match("%s-[^%s]+%s*") then
for word in text:gmatch("%s-[^%s]+%s*") do
tempWord = word:gsub("^[%s%p]-([^%s%p]+)([%-]?[^%s%p]-)[%s%p]*$","%1%2")
lowerCaseWord = tempWord:lower()
if text and match(text, "%s-[^%s]+%s*") then
for word in gmatch(text, "%s-[^%s]+%s*") do
tempWord = gsub(word, "^[%s%p]-([^%s%p]+)([%-]?[^%s%p]-)[%s%p]*$","%1%2")
lowerCaseWord = strlower(tempWord)
classMatch = CC:GetCacheTable()[E.myrealm][tempWord]
wordMatch = classMatch and lowerCaseWord
if wordMatch and not E.global.chat.classColorMentionExcludedNames[wordMatch] then
classColorTable = CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS[classMatch] or RAID_CLASS_COLORS[classMatch]
word = word:gsub(tempWord:gsub("%-","%%-"), format("\124cff%.2x%.2x%.2x%s\124r", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255, tempWord))
word = gsub(word, gsub(tempWord, "%-","%%-"), format("\124cff%.2x%.2x%.2x%s\124r", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255, tempWord))
end
if not isFirstWord then
@@ -1,13 +1,15 @@
local E, L, V, P, G = unpack(ElvUI)
local mod = E:NewModule("NamePlates", "AceHook-3.0", "AceEvent-3.0", "AceTimer-3.0")
--local CC = E:GetModule("ClassCache")
local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local mod = E:NewModule("NamePlates", "AceHook-3.0", "AceEvent-3.0", "AceTimer-3.0");
local CC = E:GetModule("ClassCache");
--Cache global variables
--Lua functions
local _G = _G
local pairs, tonumber = pairs, tonumber
local select = select
local gsub, match, split = string.gsub, string.match, string.split
local twipe = table.wipe
--WoW API / Variables
local CreateFrame = CreateFrame
local GetBattlefieldScore = GetBattlefieldScore
local GetNumBattlefieldScores = GetNumBattlefieldScores
@@ -21,7 +23,7 @@ local WorldGetNumChildren, WorldGetChildren = WorldFrame.GetNumChildren, WorldFr
local numChildren = 0
local isTarget = false
local BORDER = "Interface\\Tooltips\\Nameplate-Border"
local FSPAT = "%s*"
local FSPAT = "^%s*$"
local queryList = {}
local RaidIconCoordinate = {
@@ -269,21 +271,21 @@ function mod:RoundColors(r, g, b)
end
function mod:UnitClass(name, type)
if E.private.general.classCache then
--[[if E.private.general.classCache then
if type == "FRIENDLY_PLAYER" then
local _, class = UnitClass(name)
if class then
return class
else
local name, realm = split("-", name)
--return CC:GetClassByName(name, realm)
return CC:GetClassByName(name, realm)
end
end
else
if type == "FRIENDLY_PLAYER" then
--return select(2, UnitClass(name))
end
return select(2, UnitClass(name))
end
end--]]
end
function mod:UnitDetailedThreatSituation(frame)
@@ -300,7 +302,7 @@ function mod:UnitLevel(frame)
end
function mod:GetUnitInfo(frame)
--[[if UnitExists("target") == 1 and frame:GetParent():IsShown() and frame:GetParent():GetAlpha() == 1 then
if UnitExists("target") == 1 and frame:GetParent():IsShown() and frame:GetParent():GetAlpha() == 1 then
if UnitIsPlayer("target") then
if UnitIsEnemy("target", "player") then
return 2, "ENEMY_PLAYER"
@@ -316,7 +318,7 @@ function mod:GetUnitInfo(frame)
return 5, "FRIENDLY_NPC"
end
end
end]]
end
local r, g, b = mod:RoundColors(frame.oldHealthBar:GetStatusBarColor())
if r == 1 and g == 0 and b == 0 then
@@ -708,7 +710,7 @@ function mod:PLAYER_REGEN_ENABLED()
end
end
--[[function mod:ClassCacheQueryResult(_, name, class)
function mod:ClassCacheQueryResult(_, name, class)
if queryList[name] then
local frame = queryList[name]
@@ -726,7 +728,7 @@ end
queryList[name] = nil
end
end]]
end
function mod:Initialize()
self.db = E.db["nameplates"]
@@ -744,7 +746,7 @@ function mod:Initialize()
--self:RegisterEvent("UNIT_AURA")
--self:RegisterEvent("PLAYER_COMBO_POINTS")
--self:RegisterMessage("ClassCacheQueryResult")
self:RegisterMessage("ClassCacheQueryResult")
E.NamePlates = self
end
+10
View File
@@ -15,6 +15,16 @@ G["general"] = {
["versionCheck"] = true
}
G["classCache"] = {}
G["classtimer"] = {}
G["nameplates"] = {}
G["chat"] = {
["classColorMentionExcludedNames"] = {}
}
G["bags"] = {
["ignoredItems"] = {}
}
+2
View File
@@ -21,6 +21,8 @@ V["general"] = {
["hideCalendar"] = true,
["zoomLevel"] = 0,
},
["classCache"] = true,
["classColorMentionsSpeech"] = true,
}
V["bags"] = {
+3
View File
@@ -28,6 +28,9 @@ P["general"] = {
["backdropfadecolor"] = {r = .06, g = .06, b = .06, a = 0.8},
["valuecolor"] = {r = 254/255, g = 123/255, b = 44/255},
["classCacheStoreInDB"] = true,
["classCacheRequestInfo"] = false,
["minimap"] = {
["size"] = 176,
["locationText"] = "MOUSEOVER",
+60
View File
@@ -1,4 +1,5 @@
local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
local CC = E:GetModule("ClassCache");
E.Options.args.general = {
type = "group",
@@ -208,6 +209,65 @@ E.Options.args.general = {
min = 0, max = 4, step = 1,
get = function(info) return E.db.general.decimalLength end,
set = function(info, value) E.db.general.decimalLength = value; E:StaticPopup_Show("GLOBAL_RL") end
},
classCacheHeader = {
order = 51,
type = "header",
name = L["Class Cache"]
},
classCacheEnable = {
order = 52,
type = "toggle",
name = L["Enable"],
desc = L["Enable class caching to colorize names in chat and nameplates."],
get = function(info) return E.private.general.classCache end,
set = function(info, value)
E.private.general.classCache = value
CC:ToggleModule()
end
},
classCacheStoreInDB = {
order = 53,
type = "toggle",
name = L["Store cache in DB"],
desc = L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."],
get = function(info) return E.db.general.classCacheStoreInDB end,
set = function(info, value)
E.db.general.classCacheStoreInDB = value
CC:SwitchCacheType()
end,
disabled = function() return not E.private.general.classCache end
},
classCacheRequestInfo = {
order = 54,
type = "toggle",
name = L["Request info for class cache"],
desc = L["Use LibWho to cache class info"],
get = function(info) return E.db.general.classCacheRequestInfo end,
set = function(info, value)
E.db.general.classCacheRequestInfo = value
end,
disabled = function() return not E.private.general.classCache end
},
wipeClassCacheGlobal = {
order = 55,
type = "execute",
name = L["Wipe DB Cache"],
func = function()
CC:WipeCache(true)
GameTooltip:Hide()
end,
disabled = function() return not CC:GetCacheSize(true) end
},
wipeClassCacheLocal = {
order = 56,
type = "execute",
name = L["Wipe Session Cache"],
func = function()
CC:WipeCache()
GameTooltip:Hide()
end,
disabled = function() return not CC:GetCacheSize() end
}
}
},
@@ -310,6 +310,16 @@ Or for most users it would be easier to simply put a tga file into your WoW fold
, tga WoW , .]]
--Class Cache
L["Class Cache"] = true;
L["Enable class caching to colorize names in chat and nameplates."] = true;
L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."] = true;
L["Request info for class cache"] = true;
L["Store cache in DB"] = true;
L["Use LibWho to cache class info"] = true;
L["Wipe DB Cache"] = true;
L["Wipe Session Cache"] = true;
--Credits
L["Coding:"] = "编码:"
L["Credits"] = "呜谢"
@@ -299,6 +299,16 @@ Example: Interface\AddOns\ElvUI\media\textures\copy
Or for most users it would be easier to simply put a tga file into your WoW folder, then type the name of the file here.]] ] = true;
--Class Cache
L["Class Cache"] = true;
L["Enable class caching to colorize names in chat and nameplates."] = true;
L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."] = true;
L["Request info for class cache"] = true;
L["Store cache in DB"] = true;
L["Use LibWho to cache class info"] = true;
L["Wipe DB Cache"] = true;
L["Wipe Session Cache"] = true;
--Credits
L["Coding:"] = true;
L["Credits"] = true;
@@ -310,6 +310,16 @@ Exemple: Interface\AddOns\ElvUI\media\textures\copy
Ou pour la majorité des utilsateurs, il serait plus simple de mettre le fichier tga dans le dossier de World of Warcraft puis de taper son nom ici.]]
--Class Cache
L["Class Cache"] = true;
L["Enable class caching to colorize names in chat and nameplates."] = true;
L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."] = true;
L["Request info for class cache"] = true;
L["Store cache in DB"] = true;
L["Use LibWho to cache class info"] = true;
L["Wipe DB Cache"] = true;
L["Wipe Session Cache"] = true;
--Credits
L["Coding:"] = "Codage: "
L["Credits"] = "Crédits"
@@ -310,6 +310,16 @@ Zum Beispiel: Interface\AddOns\ElvUI\media\textures\copy
Für die meisten Anwender ist es allerdigns einfacher, eine tga-Datei in ihren WoW-Ordner abzulegen. Anschließend kann man den Namen der Datei hier eingeben.]]
--Class Cache
L["Class Cache"] = true;
L["Enable class caching to colorize names in chat and nameplates."] = true;
L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."] = true;
L["Request info for class cache"] = true;
L["Store cache in DB"] = true;
L["Use LibWho to cache class info"] = true;
L["Wipe DB Cache"] = true;
L["Wipe Session Cache"] = true;
--Credits
L["Coding:"] = "Programmierung:"
L["Credits"] = "Danksagung"
@@ -358,6 +358,16 @@ Or for most users it would be easier to simply put a tga file into your WoW fold
.]]
--Class Cache
L["Class Cache"] = true;
L["Enable class caching to colorize names in chat and nameplates."] = true;
L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."] = true;
L["Request info for class cache"] = true;
L["Store cache in DB"] = true;
L["Use LibWho to cache class info"] = true;
L["Wipe DB Cache"] = true;
L["Wipe Session Cache"] = true;
--Credits
L["Coding:"] = "|cff2eb7e4< 개발자 >|r"
L["Credits"] = "제작자"
@@ -310,6 +310,16 @@ Example: Interface\AddOns\ElvUI\media\textures\copy
Para a maioria dos usuários seria mais fácil simplesmente copiar o ficheiro tga na pasta do WoW e depois escrever o nome dele aqui.]]
--Class Cache
L["Class Cache"] = true;
L["Enable class caching to colorize names in chat and nameplates."] = true;
L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."] = true;
L["Request info for class cache"] = true;
L["Store cache in DB"] = true;
L["Use LibWho to cache class info"] = true;
L["Wipe DB Cache"] = true;
L["Wipe Session Cache"] = true;
--Credits
L["Coding:"] = "Codificação:"
L["Credits"] = "Créditos"
@@ -310,6 +310,16 @@ Or for most users it would be easier to simply put a tga file into your WoW fold
Для большинства пользователей будет легче просто положить tga файл в папку игры, а затем написать имя файла здесь.]]
--Class Cache
L["Class Cache"] = true;
L["Enable class caching to colorize names in chat and nameplates."] = true;
L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."] = true;
L["Request info for class cache"] = true;
L["Store cache in DB"] = true;
L["Use LibWho to cache class info"] = true;
L["Wipe DB Cache"] = true;
L["Wipe Session Cache"] = true;
--Credits
L["Coding:"] = "Написание кода:"
L["Credits"] = "Благодарности"
@@ -310,6 +310,16 @@ Ejemplo: Interface\AddOns\ElvUI\media\textures\copy
O también puedes simplemente colocar un archivo tga en la carpeta de WoW, y escribir aquí el nombre del archivo.]]
--Class Cache
L["Class Cache"] = true;
L["Enable class caching to colorize names in chat and nameplates."] = true;
L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."] = true;
L["Request info for class cache"] = true;
L["Store cache in DB"] = true;
L["Use LibWho to cache class info"] = true;
L["Wipe DB Cache"] = true;
L["Wipe Session Cache"] = true;
--Credits
L["Coding:"] = "Codificación:"
L["Credits"] = "Créditos"
@@ -310,6 +310,16 @@ Or for most users it would be easier to simply put a tga file into your WoW fold
, tga WoW , .]]
--Class Cache
L["Class Cache"] = true;
L["Enable class caching to colorize names in chat and nameplates."] = true;
L["If cache stored in DB it will be available between game sessions but increase memory usage.\nIn other way it will be wiped on relog or UI reload."] = true;
L["Request info for class cache"] = true;
L["Store cache in DB"] = true;
L["Use LibWho to cache class info"] = true;
L["Wipe DB Cache"] = true;
L["Wipe Session Cache"] = true;
--Credits
L["Coding:"] = "編碼:"
L["Credits"] = "嗚謝"