mirror of
https://github.com/Bluewhale1337/ElvUIModernized.git
synced 2026-07-27 08:24:44 +00:00
load LibWho-2.0, ClassCache & update Chat
update Chat
This commit is contained in:
@@ -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)
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -15,6 +15,16 @@ G["general"] = {
|
||||
["versionCheck"] = true
|
||||
}
|
||||
|
||||
G["classCache"] = {}
|
||||
|
||||
G["classtimer"] = {}
|
||||
|
||||
G["nameplates"] = {}
|
||||
|
||||
G["chat"] = {
|
||||
["classColorMentionExcludedNames"] = {}
|
||||
}
|
||||
|
||||
G["bags"] = {
|
||||
["ignoredItems"] = {}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ V["general"] = {
|
||||
["hideCalendar"] = true,
|
||||
["zoomLevel"] = 0,
|
||||
},
|
||||
["classCache"] = true,
|
||||
["classColorMentionsSpeech"] = true,
|
||||
}
|
||||
|
||||
V["bags"] = {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"] = "嗚謝"
|
||||
|
||||
Reference in New Issue
Block a user