You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
467 lines
13 KiB
467 lines
13 KiB
--[[
|
|
Name: LibAlts-1.0
|
|
Revision: 50
|
|
Author: Sylvanaar (sylvanaar@mindspring.com)
|
|
Description: Shared handling of alt identity between addons.
|
|
Dependencies: LibStub
|
|
License:
|
|
]]--
|
|
|
|
local MAJOR, MINOR = "LibAlts-1.0", 1
|
|
local LibStub = LibStub
|
|
local lib = LibStub:NewLibrary(MAJOR, MINOR)
|
|
if not lib then return end
|
|
|
|
local _G = getfenv(0)
|
|
|
|
lib.Alts = lib.Alts or {}
|
|
lib.AltsPerSource = lib.AltsPerSource or {}
|
|
lib.RealIds = lib.RealIds or {}
|
|
|
|
local Alts = lib.Alts
|
|
local AltsPerSource = lib.AltsPerSource
|
|
|
|
local Mains -- reverse lookup table
|
|
local MainsPerSource = {} -- reverse lookup table
|
|
|
|
--local RealIds = lib.RealIds
|
|
--local RealIdMains = {} -- reverse lookup table
|
|
|
|
local tinsert = _G.tinsert
|
|
local unpack = _G.unpack
|
|
local pairs = _G.pairs
|
|
local tremove = _G.tremove
|
|
local tsort = _G.table.sort
|
|
local tContains = _G.tContains
|
|
local ipairs = _G.ipairs
|
|
local wipe = _G.wipe
|
|
|
|
lib.callbacks = lib.callbacks or LibStub("CallbackHandler-1.0"):New(lib)
|
|
local callbacks = lib.callbacks
|
|
|
|
-- Regexp to match the first character for UTF8 strings
|
|
local MULTIBYTE_FIRST_CHAR = "^([\192-\255]?%a?[\128-\191]*)"
|
|
|
|
-- Constants for the source prefixes. These should be prepended for guild or
|
|
-- addon source names so they remain consistent. The guild name itself should
|
|
-- be the exact value from the Blizzard API. Addons should use their exact name.
|
|
lib.GUILD_PREFIX = "guild:"
|
|
lib.ADDON_PREFIX = "addon:"
|
|
|
|
local function reverseTable(table)
|
|
local reverse = {}
|
|
|
|
if table then
|
|
for k,v in pairs(table) do
|
|
for i,a in ipairs(v) do
|
|
reverse[a] = k
|
|
end
|
|
end
|
|
end
|
|
|
|
return reverse
|
|
end
|
|
|
|
--- Register a Main-Alt relationship.
|
|
-- User-entered data should not have a source (i.e, source = nil). For guild data,
|
|
-- prepend "guild:" to the guild name returned from the API. Addons
|
|
-- wishing to add their own separate data should prepend "addon:". Any data not
|
|
-- directly entered by a user should be added as a source.
|
|
-- @name :SetAlt
|
|
-- @param main Name of the main character.
|
|
-- @param alt Name of the alt character.
|
|
-- @param source Source of the main-alt relationship. Nil if used-defined.
|
|
function lib:SetAlt(main, alt, source)
|
|
if (not main) or (not alt) then return end
|
|
|
|
main = self:TitleCase(main)
|
|
alt = self:TitleCase(alt)
|
|
|
|
if not source then
|
|
-- Adding the relationship to the user-defined data.
|
|
Mains = nil
|
|
|
|
Alts[main] = Alts[main] or {}
|
|
for i,v in ipairs(Alts[main]) do
|
|
if v == alt then
|
|
return
|
|
end
|
|
end
|
|
tinsert(Alts[main], alt)
|
|
else
|
|
-- Adding a relationship for a specific source.
|
|
MainsPerSource[source] = nil
|
|
|
|
AltsPerSource[source] = AltsPerSource[source] or {}
|
|
AltsPerSource[source][main] = AltsPerSource[source][main] or {}
|
|
for i,v in ipairs(AltsPerSource[source][main]) do
|
|
if v == alt then
|
|
return
|
|
end
|
|
end
|
|
tinsert(AltsPerSource[source][main], alt)
|
|
end
|
|
|
|
callbacks:Fire("LibAlts_SetAlt", main, alt, source)
|
|
end
|
|
|
|
--- Get a list of alts for a given character.
|
|
-- @name :GetAlts
|
|
-- @param main Name of the main character.
|
|
-- @return list list of alts.
|
|
function lib:GetAlts(main)
|
|
if not main then return nil end
|
|
|
|
main = self:TitleCase(main)
|
|
|
|
local alts = {}
|
|
|
|
if Alts[main] and #Alts[main] > 0 then
|
|
for i, v in ipairs(Alts[main]) do
|
|
if not tContains(alts, v) then
|
|
tinsert(alts, v)
|
|
end
|
|
end
|
|
end
|
|
|
|
for k, v in pairs(AltsPerSource) do
|
|
if AltsPerSource[k][main] and #AltsPerSource[k][main] > 0 then
|
|
for i, v in ipairs(AltsPerSource[k][main]) do
|
|
if not tContains(alts, v) then
|
|
tinsert(alts, v)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if #alts > 0 then
|
|
return unpack(alts)
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--- Get a list of alts for a given character for a given data source.
|
|
-- @name :GetAltsForSource
|
|
-- @param main Name of the main character.
|
|
-- @param source The data source to use. Nil for user-defined.
|
|
-- @return list list of alts.
|
|
function lib:GetAltsForSource(main, source)
|
|
if not main then return end
|
|
|
|
main = self:TitleCase(main)
|
|
|
|
if not source then
|
|
if Alts[main] and #Alts[main] > 0 then
|
|
return unpack(Alts[main])
|
|
end
|
|
else
|
|
if not AltsPerSource[source] then return nil end
|
|
if AltsPerSource[source][main] and #AltsPerSource[source][main] > 0 then
|
|
return unpack(AltsPerSource[source][main])
|
|
end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--- Get the main for a given alt character.
|
|
-- @name :GetMain
|
|
-- @param alt Name of the alt character.
|
|
-- @return string the main character.
|
|
function lib:GetMain(alt)
|
|
if not alt then return end
|
|
|
|
alt = self:TitleCase(alt)
|
|
|
|
if not Mains then
|
|
Mains = reverseTable(Alts)
|
|
end
|
|
|
|
-- Check the user-defined data first.
|
|
local main = Mains[alt]
|
|
if main then return main end
|
|
|
|
-- Check the various data sources.
|
|
for k, v in pairs(AltsPerSource) do
|
|
-- Check that the reverse table is built for the data source
|
|
if not MainsPerSource[k] then
|
|
MainsPerSource[k] = reverseTable(AltsPerSource[k])
|
|
end
|
|
|
|
main = MainsPerSource[k][alt]
|
|
if main then return main end
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
--- Get the main for a given alt character for a given data source.
|
|
-- @name :GetMainForSource
|
|
-- @param alt Name of the alt character.
|
|
-- @param source The data source to use.
|
|
-- @return string the main character.
|
|
function lib:GetMainForSource(alt, source)
|
|
if not alt then return nil end
|
|
|
|
alt = self:TitleCase(alt)
|
|
|
|
if not source then
|
|
if not Mains then
|
|
Mains = reverseTable(Alts)
|
|
end
|
|
|
|
return Mains[alt]
|
|
else
|
|
if not AltsPerSource[source] then return nil end
|
|
|
|
if not MainsPerSource[source] then
|
|
MainsPerSource[source] = reverseTable(AltsPerSource[source])
|
|
end
|
|
|
|
return MainsPerSource[source][alt]
|
|
end
|
|
end
|
|
|
|
--- Return a table of all main characters.
|
|
-- @name :GetAllMains
|
|
-- @param mains The table to fill with the mains.
|
|
function lib:GetAllMains(mains)
|
|
if not mains then return end
|
|
|
|
for k, v in pairs(Alts) do
|
|
if not tContains(mains, k) then
|
|
tinsert(mains, k)
|
|
end
|
|
end
|
|
|
|
for k, v in pairs(AltsPerSource) do
|
|
for key, val in pairs(AltsPerSource[k]) do
|
|
if not tContains(mains, key) then
|
|
tinsert(mains, key)
|
|
end
|
|
end
|
|
end
|
|
|
|
return mains
|
|
end
|
|
|
|
--- Return a table of all main characters for a given data source.
|
|
-- @name :GetAllMainsForSource
|
|
-- @param mains The table to fill with the mains.
|
|
-- @param source The data source to limit the mains for. Nil for user-defined.
|
|
function lib:GetAllMainsForSource(mains, source)
|
|
if not mains then return end
|
|
|
|
if not source then
|
|
for k, v in pairs(Alts) do
|
|
tinsert(mains, k)
|
|
end
|
|
else
|
|
if not AltsPerSource[source] then return nil end
|
|
|
|
for k, v in pairs(AltsPerSource[source]) do
|
|
tinsert(mains, k)
|
|
end
|
|
end
|
|
|
|
return mains
|
|
end
|
|
|
|
--- Test if a character is a main.
|
|
-- @name :IsMain
|
|
-- @param main Name of the character.
|
|
-- @return boolean is this a main character.
|
|
function lib:IsMain(main)
|
|
if not main then return nil end
|
|
|
|
main = self:TitleCase(main)
|
|
|
|
if Alts[main] then return true end
|
|
|
|
for k, v in pairs(AltsPerSource) do
|
|
if AltsPerSource[k][main] then return true end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
--- Test if a character is a main for a given data source.
|
|
-- @name :IsMainForSource
|
|
-- @param main Name of the character.
|
|
-- @param source The data source to use. Nil for user-defined.
|
|
-- @return boolean is this a main character.
|
|
function lib:IsMainForSource(main, source)
|
|
if not main then return nil end
|
|
|
|
main = self:TitleCase(main)
|
|
|
|
if not source then
|
|
return Alts[main] and true or false
|
|
else
|
|
if not AltsPerSource[source] then return false end
|
|
return AltsPerSource[source][main] and true or false
|
|
end
|
|
end
|
|
|
|
--- Test if a character is an alt.
|
|
-- @name :IsAlt
|
|
-- @param alt Name of the character.
|
|
-- @return boolean is this a alt character.
|
|
function lib:IsAlt(alt)
|
|
if not alt then return nil end
|
|
|
|
alt = self:TitleCase(alt)
|
|
|
|
if not Mains then
|
|
Mains = reverseTable(Alts)
|
|
end
|
|
|
|
if Mains[alt] then return true end
|
|
|
|
for k, v in pairs(AltsPerSource) do
|
|
if not MainsPerSource[k] then
|
|
MainsPerSource[k] = reverseTable(AltsPerSource[k])
|
|
end
|
|
|
|
if MainsPerSource[k][alt] then return true end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
--- Test if a character is an alt for a given data source.
|
|
-- @name :IsAltForSource
|
|
-- @param alt Name of the character.
|
|
-- @param source The data source to use. Nil for user-defined.
|
|
-- @return boolean is this a alt character.
|
|
function lib:IsAltForSource(alt, source)
|
|
if not alt then return nil end
|
|
|
|
alt = self:TitleCase(alt)
|
|
|
|
if not source then
|
|
if not Mains then
|
|
Mains = reverseTable(Alts)
|
|
end
|
|
|
|
return Mains[alt] and true or false
|
|
else
|
|
if not AltsPerSource[source] then return false end
|
|
|
|
if not MainsPerSource[source] then
|
|
MainsPerSource[source] = reverseTable(AltsPerSource[source])
|
|
end
|
|
|
|
return MainsPerSource[source][alt] and true or false
|
|
end
|
|
end
|
|
|
|
--- Remove a Main-Alt relationship and fire a callback for the disassociation.
|
|
-- @name :DeleteAlt
|
|
-- @param main Name of the Main character.
|
|
-- @param alt Name of the Alt being removed.
|
|
-- @param source Source of the main-alt relationship. Nil if used-defined.
|
|
function lib:DeleteAlt(main, alt, source)
|
|
main, alt = self:TitleCase(main), self:TitleCase(alt)
|
|
|
|
if not source then
|
|
if not Alts[main] then return end
|
|
Mains = nil
|
|
for i = 1, #Alts[main] do
|
|
if Alts[main][i] == alt then
|
|
tremove(Alts[main], i)
|
|
end
|
|
end
|
|
if #Alts[main] == 0 then
|
|
Alts[main] = nil
|
|
end
|
|
else
|
|
if not AltsPerSource[source] or not AltsPerSource[source][main] then return end
|
|
MainsPerSource[source] = nil
|
|
for i = 1, #AltsPerSource[source][main] do
|
|
if AltsPerSource[source][main][i] == alt then
|
|
tremove(AltsPerSource[source][main], i)
|
|
end
|
|
end
|
|
if #AltsPerSource[source][main] == 0 then
|
|
AltsPerSource[source][main] = nil
|
|
end
|
|
end
|
|
callbacks:Fire("LibAlts_RemoveAlt", main, alt, source) --Alt is the one removed
|
|
end
|
|
|
|
--- Remove a data source, including all main-alt relationships, and fire a callback.
|
|
-- @name :RemoveSource
|
|
-- @param source Data source to be removed.
|
|
function lib:RemoveSource(source)
|
|
if AltsPerSource[source] then
|
|
wipe(AltsPerSource[source])
|
|
AltsPerSource[source] = nil
|
|
end
|
|
if MainsPerSource[source] then
|
|
wipe(MainsPerSource[source])
|
|
MainsPerSource[source] = nil
|
|
end
|
|
callbacks:Fire("LibAlts_RemoveSource", source)
|
|
end
|
|
|
|
--- Returns a name formatted in title case (i.e., first character upper case, the rest lower).
|
|
-- @name :TitleCase
|
|
-- @param name The name to be converted.
|
|
-- @return string The converted name.
|
|
function lib:TitleCase(name)
|
|
if not name then return "" end
|
|
if #name == 0 then return "" end
|
|
|
|
name = name:lower()
|
|
return name:gsub(MULTIBYTE_FIRST_CHAR, string.upper, 1)
|
|
end
|
|
|
|
--[[
|
|
--- Get the main for a given Real Id name.
|
|
-- @name :GetMainForRealId
|
|
-- @param realid The Real Id name.
|
|
-- @return string The main character name, if a mapping exists.
|
|
function lib:GetMainForRealId(realid)
|
|
if not realid then return nil end
|
|
realid = self:TitleCase(realid)
|
|
return RealIds[realid]
|
|
end
|
|
|
|
--- Get the Real ID name for a given main character.
|
|
-- @name :GetRealIdForMain
|
|
-- @param main Name of the main character.
|
|
-- @return string The Real Id name for the main, if a mapping exists.
|
|
function lib:GetRealIdForMain(main)
|
|
if not main then return nil end
|
|
main = self:TitleCase(main)
|
|
return RealIdMains[main]
|
|
end
|
|
|
|
--- Register a Real Id-Main relationship.
|
|
-- @name :SetRealIdForMain
|
|
-- @param realid The Real Id name.
|
|
-- @param main Name of the main character.
|
|
function lib:SetRealIdForMain(realid, main)
|
|
if not realid or or #realid == 0 or not main or #main == 0 then return nil end
|
|
main = self:TitleCase(main)
|
|
realid = self:TitleCase(realid)
|
|
|
|
-- Add the forward and reverse mappings
|
|
RealIds[realid] = main
|
|
RealIdMains[main] = realid
|
|
|
|
callbacks:Fire("LibAlts_SetRealIdForMain", realid, main)
|
|
end
|
|
|
|
--- Test if a Real Id-Main relationship exists for a given Real Id name.
|
|
-- @name :IsRealId
|
|
-- @param realid The Real Id name.
|
|
-- @return boolean Does the Real Id-Main relationship exist.
|
|
function lib:IsRealId(realid)
|
|
if not realid then return nil end
|
|
|
|
return RealIds[realid] and true or false
|
|
end
|
|
]]--
|
|
|