Files
coa-atlasloot/AtlasLootFu/Libs/AceDB-2.0/AceDB-2.0.lua
T
2020-06-01 22:15:40 -04:00

2222 lines
64 KiB
Lua

--[[
Name: AceDB-2.0
Revision: $Rev: 1094 $
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
Website: http://www.wowace.com/
Documentation: http://www.wowace.com/index.php/AceDB-2.0
SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceDB-2.0
Description: Mixin to allow for fast, clean, and featureful saved variable
access.
Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0
License: LGPL v2.1
]]
local MAJOR_VERSION = "AceDB-2.0"
local MINOR_VERSION = 90000 + tonumber(("$Revision: 1094 $"):match("(%d+)"))
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
local function safecall(func,...)
local success, err = pcall(func,...)
if not success then geterrorhandler()(err) end
end
local ACTIVE, ENABLED, STATE, TOGGLE_ACTIVE, MAP_ACTIVESUSPENDED, SET_PROFILE, SET_PROFILE_USAGE, PROFILE, PLAYER_OF_REALM, CHOOSE_PROFILE_DESC, CHOOSE_PROFILE_GUI, COPY_PROFILE_DESC, COPY_PROFILE_GUI, OTHER_PROFILE_DESC, OTHER_PROFILE_GUI, OTHER_PROFILE_USAGE, RESET_PROFILE, RESET_PROFILE_DESC, CHARACTER_COLON, REALM_COLON, CLASS_COLON, DEFAULT, ALTERNATIVE
-- Move these into "enUS" when they've been translated in all other locales
local DELETE_PROFILE = "Delete"
local DELETE_PROFILE_DESC = "Deletes a profile. Note that no check is made whether this profile is in use by other characters or not."
local DELETE_PROFILE_USAGE = "<profile name>"
if GetLocale() == "deDE" then
DELETE_PROFILE = "L\195\182schen"
DELETE_PROFILE_DESC = "L\195\182scht ein Profil. Beachte das nicht \195\188berpr\195\188ft wird ob das zu l\195\182schende Profil von anderen Charakteren genutzt wird oder nicht."
DELETE_PROFILE_USAGE = "<profil name>"
ACTIVE = "Aktiv"
ENABLED = "Aktiviert"
STATE = "Status"
TOGGLE_ACTIVE = "Stoppt/Aktiviert dieses Addon."
MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Aktiv|r", [false] = "|cffff0000Gestoppt|r" }
SET_PROFILE = "Setzt das Profil f\195\188r dieses Addon."
SET_PROFILE_USAGE = "{Charakter || Klasse || Realm || <Profilname>}"
PROFILE = "Profil"
PLAYER_OF_REALM = "%s von %s"
CHOOSE_PROFILE_DESC = "W\195\164hle ein Profil."
CHOOSE_PROFILE_GUI = "W\195\164hle"
COPY_PROFILE_DESC = "Kopiert Einstellungen von einem anderem Profil."
COPY_PROFILE_GUI = "Kopiere von"
OTHER_PROFILE_DESC = "W\195\164hle ein anderes Profil."
OTHER_PROFILE_GUI = "Anderes"
OTHER_PROFILE_USAGE = "<Profilname>"
RESET_PROFILE = "Resette das Profil"
RESET_PROFILE_DESC = "Entfernt alle Einstellungen des gegenw\195\164rtigen Profils."
CHARACTER_COLON = "Charakter: "
REALM_COLON = "Realm: "
CLASS_COLON = "Klasse: "
DEFAULT = "Vorgabe"
ALTERNATIVE = "Alternativ"
elseif GetLocale() == "frFR" then
ACTIVE = "Actif"
ENABLED = "Activ\195\169"
STATE = "Etat"
TOGGLE_ACTIVE = "Suspend/active cet addon."
MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Actif|r", [false] = "|cffff0000Suspendu|r" }
SET_PROFILE = "S\195\169lectionne le profil pour cet addon."
SET_PROFILE_USAGE = "{perso || classe || royaume || <nom de profil>}"
PROFILE = "Profil"
PLAYER_OF_REALM = "%s de %s"
CHOOSE_PROFILE_DESC = "Choisissez un profil."
CHOOSE_PROFILE_GUI = "Choix"
COPY_PROFILE_DESC = "Copier les param\195\168tres d'un autre profil."
COPY_PROFILE_GUI = "Copier \195\160 partir de"
OTHER_PROFILE_DESC = "Choisissez un autre profil."
OTHER_PROFILE_GUI = "Autre"
OTHER_PROFILE_USAGE = "<nom de profil>"
RESET_PROFILE = "Reset profile" -- fix
RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix
CHARACTER_COLON = "Personnage: "
REALM_COLON = "Royaume: "
CLASS_COLON = "Classe: "
DEFAULT = "Default" -- fix
ALTERNATIVE = "Alternative" -- fix
elseif GetLocale() == "koKR" then
DELETE_PROFILE = "삭제"
DELETE_PROFILE_DESC = "프로필을 삭제합니다."
DELETE_PROFILE_USAGE = "<프로필명>"
ACTIVE = "사용"
ENABLED = "사용"
STATE = "상태"
TOGGLE_ACTIVE = "이 애드온 중지/다시 시작"
MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00사용|r", [false] = "|cffff0000중지|r" }
SET_PROFILE = "이 애드온에 프로필 설정"
SET_PROFILE_USAGE = "{캐릭터명 || 직업 || 서버명 || <프로필명>}"
PROFILE = "프로필"
PLAYER_OF_REALM = "%s (%s 서버)"
CHOOSE_PROFILE_DESC = "프로필을 선택합니다."
CHOOSE_PROFILE_GUI = "선택"
COPY_PROFILE_DESC = "다른 프로필 설정을 복사합니다."
COPY_PROFILE_GUI = "복사"
OTHER_PROFILE_DESC = "다른 프로필을 선택합니다."
OTHER_PROFILE_GUI = "기타"
OTHER_PROFILE_USAGE = "<프로필명>"
RESET_PROFILE = "프로필 초기화"
RESET_PROFILE_DESC = "모든 세팅에서 현재 프로필을 초기화 합니다."
CHARACTER_COLON = "캐릭터: "
REALM_COLON = "서버: "
CLASS_COLON = "직업: "
DEFAULT = "기본값"
ALTERNATIVE = "대체"
elseif GetLocale() == "zhTW" then
DELETE_PROFILE = "刪除"
DELETE_PROFILE_DESC = "刪除記錄檔。注意,有可能別的角色也使用這個記錄檔。"
DELETE_PROFILE_USAGE = "<記錄檔名稱>"
ACTIVE = "啟動"
ENABLED = "啟用"
STATE = "狀態"
TOGGLE_ACTIVE = "暫停/繼續使用這個插件。"
MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00啟動|r", [false] = "|cffff0000已暫停|r" }
SET_PROFILE = "設定這插件的記錄檔。"
SET_PROFILE_USAGE = "{角色 || 職業 || 伺服器 || <記錄檔名稱>}"
PROFILE = "記錄檔"
PLAYER_OF_REALM = "%s - %s"
CHOOSE_PROFILE_DESC = "選擇一個記錄檔。"
CHOOSE_PROFILE_GUI = "選擇"
COPY_PROFILE_DESC = "由其他記錄檔複製設定。"
COPY_PROFILE_GUI = "複製自"
OTHER_PROFILE_DESC = "選擇其他記錄檔。"
OTHER_PROFILE_GUI = "其他"
OTHER_PROFILE_USAGE = "<記錄檔名稱>"
RESET_PROFILE = "重設記錄檔"
RESET_PROFILE_DESC = "清除目前的記錄檔上的所有設定。"
CHARACTER_COLON = "角色: "
REALM_COLON = "伺服器: "
CLASS_COLON = "職業: "
DEFAULT = "預設"
ALTERNATIVE = "替代"
elseif GetLocale() == "zhCN" then
ACTIVE = "\230\156\137\230\149\136"
ENABLED = "\229\144\175\231\148\168"
STATE = "\231\138\182\230\128\129"
TOGGLE_ACTIVE = "\230\154\130\229\129\156/\230\129\162\229\164\141 \230\173\164\230\143\146\228\187\182."
MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00\230\156\137\230\149\136|r", [false] = "|cffff0000\230\154\130\229\129\156|r" }
SET_PROFILE = "\232\174\190\231\189\174\233\133\141\231\189\174\230\150\135\228\187\182\228\184\186\232\191\153\230\143\146\228\187\182."
SET_PROFILE_USAGE = "{\229\173\151\231\172\166 || \233\128\137\228\187\182\231\177\187 || \229\159\159 || <\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>}"
PROFILE = "\233\133\141\231\189\174\230\150\135\228\187\182"
PLAYER_OF_REALM = "%s \231\154\132 %s"
CHOOSE_PROFILE_DESC = "\233\128\137\230\139\169\233\133\141\231\189\174\230\150\135\228\187\182."
CHOOSE_PROFILE_GUI = "\233\128\137\230\139\169"
COPY_PROFILE_DESC = "\229\164\141\229\136\182\232\174\190\231\189\174\228\187\142\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182."
COPY_PROFILE_GUI = "\229\164\141\229\136\182\228\187\142"
OTHER_PROFILE_DESC = "\233\128\137\230\139\169\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182."
OTHER_PROFILE_GUI = "\229\133\182\228\187\150"
OTHER_PROFILE_USAGE = "<\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>"
RESET_PROFILE = "Reset profile" -- fix
RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix
CHARACTER_COLON = "\229\173\151\231\172\166: "
REALM_COLON = "\229\159\159: "
CLASS_COLON = "\233\128\137\228\187\182\231\177\187: "
DEFAULT = "Default" -- fix
ALTERNATIVE = "Alternative" -- fix
elseif GetLocale() == "esES" then
ACTIVE = "Activo"
ENABLED = "Activado"
STATE = "Estado"
TOGGLE_ACTIVE = "Parar/Continuar este accesorio"
MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Activo|r", [false] = "|cffff0000Parado|r" }
SET_PROFILE = "Selecciona el perfil para este accesorio."
SET_PROFILE_USAGE = "{perso || clase || reino || <nombre del perfil>}"
PROFILE = "Perfil"
PLAYER_OF_REALM = "%s de %s"
CHOOSE_PROFILE_DESC = "Elige un perfil."
CHOOSE_PROFILE_GUI = "Elige"
COPY_PROFILE_DESC = "Copiar de un perfil a otro"
COPY_PROFILE_GUI = "Copiar desde"
OTHER_PROFILE_DESC = "Elige otro perfil."
OTHER_PROFILE_GUI = "Otro"
OTHER_PROFILE_USAGE = "<nombre del perfil>"
RESET_PROFILE = "Reset profile" -- fix
RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix
CHARACTER_COLON = "Personaje: "
REALM_COLON = "Reino: "
CLASS_COLON = "Clase: "
DEFAULT = "Por defecto"
ALTERNATIVE = "Alternativo"
elseif GetLocale() == "ruRU" then
DELETE_PROFILE = "Удалить"
DELETE_PROFILE_DESC = "Удалить профиль. Изначально проверьте не используется ли этот профиль другими персонажами, чтобы не натворить себе неудобств."
DELETE_PROFILE_USAGE = "<название профиля>"
ACTIVE = "Активный"
ENABLED = "Включён"
STATE = "Состояние"
TOGGLE_ACTIVE = "Отключить/Запустить аддон."
MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Активный|r", [false] = "|cffff0000Suspended|r" }
SET_PROFILE = "Установить профиль для этого аддона."
SET_PROFILE_USAGE = "{чар || класс || сервер || <название профиля>}"
PROFILE = "Профиль"
PLAYER_OF_REALM = "%s из %s"
CHOOSE_PROFILE_DESC = "Выберите профиль."
CHOOSE_PROFILE_GUI = "Выбор"
COPY_PROFILE_DESC = "Скопировать настройки из другого профиля."
COPY_PROFILE_GUI = "Скопировать из"
OTHER_PROFILE_DESC = "Выбрать другой профиль."
OTHER_PROFILE_GUI = "Другое"
OTHER_PROFILE_USAGE = "<название профиля>"
RESET_PROFILE = "Сброс профиля"
RESET_PROFILE_DESC = "Очистить все настройки для текущего профиля."
CHARACTER_COLON = "Персонаж: "
REALM_COLON = "Сервер: "
CLASS_COLON = "Класс: "
DEFAULT = "По-умолчанию"
ALTERNATIVE = "Альтернатива"
else -- enUS
ACTIVE = "Active"
ENABLED = "Enabled"
STATE = "State"
TOGGLE_ACTIVE = "Suspend/resume this addon."
MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Active|r", [false] = "|cffff0000Suspended|r" }
SET_PROFILE = "Set profile for this addon."
SET_PROFILE_USAGE = "{char || class || realm || <profile name>}"
PROFILE = "Profile"
PLAYER_OF_REALM = "%s of %s"
CHOOSE_PROFILE_DESC = "Choose a profile."
CHOOSE_PROFILE_GUI = "Choose"
COPY_PROFILE_DESC = "Copy settings from another profile."
COPY_PROFILE_GUI = "Copy from"
OTHER_PROFILE_DESC = "Choose another profile."
OTHER_PROFILE_GUI = "Other"
OTHER_PROFILE_USAGE = "<profile name>"
RESET_PROFILE = "Reset profile"
RESET_PROFILE_DESC = "Clear all settings of the current profile."
CHARACTER_COLON = "Character: "
REALM_COLON = "Realm: "
CLASS_COLON = "Class: "
DEFAULT = "Default"
ALTERNATIVE = "Alternative"
end
local convertFromOldCharID
do
local matchStr = "^" .. PLAYER_OF_REALM:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1"):gsub("%%s", "(.+)") .. "$"
function convertFromOldCharID(str)
local player, realm = str:match(matchStr)
if not player then
return str
end
return player .. " - " .. realm
end
end
local AceOO = AceLibrary("AceOO-2.0")
local AceEvent
local Mixin = AceOO.Mixin
local AceDB = Mixin {
"RegisterDB",
"RegisterDefaults",
"ResetDB",
"SetProfile",
"GetProfile",
"CopyProfileFrom",
"DeleteProfile",
"ToggleActive",
"IsActive",
"AcquireDBNamespace",
}
local Dewdrop = AceLibrary:HasInstance("Dewdrop-2.0") and AceLibrary("Dewdrop-2.0")
local _G = getfenv(0)
local function inheritDefaults(t, defaults)
if not defaults then
return t
end
for k,v in pairs(defaults) do
if k == "*" or k == "**" then
local v = v
if type(v) == "table" then
setmetatable(t, {
__index = function(self, key)
if key == nil then
return nil
end
self[key] = {}
inheritDefaults(self[key], v)
return self[key]
end
} )
else
setmetatable(t, {
__index = function(self, key)
if key == nil then
return nil
end
self[key] = v
return self[key]
end
} )
end
for key in pairs(t) do
if (defaults[key] == nil or key == k) and type(t[key]) == "table" then
inheritDefaults(t[key], v)
end
end
else
if type(v) == "table" then
if type(rawget(t, k)) ~= "table" then
t[k] = {}
end
inheritDefaults(t[k], v)
if defaults["**"] then
inheritDefaults(t[k], defaults["**"])
end
elseif rawget(t, k) == nil then
t[k] = v
end
end
end
return t
end
local _,race = UnitRace("player")
local faction
if race == "Orc" or race == "Scourge" or race == "Troll" or race == "Tauren" or race == "BloodElf" then
faction = FACTION_HORDE
else
faction = FACTION_ALLIANCE
end
local server = GetRealmName():trim()
local charID = UnitName("player") .. " - " .. server
local realmID = server .. " - " .. faction
local classID = UnitClass("player")
AceDB.CHAR_ID = charID
AceDB.REALM_ID = realmID
AceDB.CLASS_ID = classID
AceDB.FACTION = faction
AceDB.REALM = server
AceDB.NAME = UnitName("player")
local new, del
do
local list = setmetatable({}, {__mode="k"})
function new()
local t = next(list)
if t then
list[t] = nil
return t
else
return {}
end
end
function del(t)
setmetatable(t, nil)
for k in pairs(t) do
t[k] = nil
end
list[t] = true
end
end
local caseInsensitive_mt = {
__index = function(self, key)
if type(key) ~= "string" then
return nil
end
local lowerKey = key:lower()
for k,v in pairs(self) do
if k:lower() == lowerKey then
return self[k]
end
end
end,
__newindex = function(self, key, value)
if type(key) ~= "string" then
return error("table index is nil", 2)
end
local lowerKey = key:lower()
for k in pairs(self) do
if k:lower() == lowerKey then
rawset(self, k, nil)
rawset(self, key, value)
return
end
end
rawset(self, key, value)
end
}
local db_mt = { __index = function(db, key)
if key == "char" then
if db.charName then
if type(_G[db.charName]) ~= "table" then
_G[db.charName] = {}
end
if type(_G[db.charName].global) ~= "table" then
_G[db.charName].global = {}
end
rawset(db, 'char', _G[db.charName].global)
else
if type(db.raw.chars) ~= "table" then
db.raw.chars = {}
end
local id = charID
if type(db.raw.chars[id]) ~= "table" then
db.raw.chars[id] = {}
end
rawset(db, 'char', db.raw.chars[id])
end
if db.defaults and db.defaults.char then
inheritDefaults(db.char, db.defaults.char)
end
return db.char
elseif key == "realm" then
if type(db.raw.realms) ~= "table" then
db.raw.realms = {}
end
local id = realmID
if type(db.raw.realms[id]) ~= "table" then
db.raw.realms[id] = {}
end
rawset(db, 'realm', db.raw.realms[id])
if db.defaults and db.defaults.realm then
inheritDefaults(db.realm, db.defaults.realm)
end
return db.realm
elseif key == "server" then
if type(db.raw.servers) ~= "table" then
db.raw.servers = {}
end
local id = server
if type(db.raw.servers[id]) ~= "table" then
db.raw.servers[id] = {}
end
rawset(db, 'server', db.raw.servers[id])
if db.defaults and db.defaults.server then
inheritDefaults(db.server, db.defaults.server)
end
return db.server
elseif key == "account" then
if type(db.raw.account) ~= "table" then
db.raw.account = {}
end
rawset(db, 'account', db.raw.account)
if db.defaults and db.defaults.account then
inheritDefaults(db.account, db.defaults.account)
end
return db.account
elseif key == "faction" then
if type(db.raw.factions) ~= "table" then
db.raw.factions = {}
end
local id = faction
if type(db.raw.factions[id]) ~= "table" then
db.raw.factions[id] = {}
end
rawset(db, 'faction', db.raw.factions[id])
if db.defaults and db.defaults.faction then
inheritDefaults(db.faction, db.defaults.faction)
end
return db.faction
elseif key == "class" then
if type(db.raw.classes) ~= "table" then
db.raw.classes = {}
end
local id = classID
if type(db.raw.classes[id]) ~= "table" then
db.raw.classes[id] = {}
end
rawset(db, 'class', db.raw.classes[id])
if db.defaults and db.defaults.class then
inheritDefaults(db.class, db.defaults.class)
end
return db.class
elseif key == "profile" then
if type(db.raw.profiles) ~= "table" then
db.raw.profiles = setmetatable({}, caseInsensitive_mt)
else
setmetatable(db.raw.profiles, caseInsensitive_mt)
end
local id = db.raw.currentProfile[charID]
if id == "char" then
id = "char/" .. charID
elseif id == "class" then
id = "class/" .. classID
elseif id == "realm" then
id = "realm/" .. realmID
end
if type(db.raw.profiles[id]) ~= "table" then
db.raw.profiles[id] = {}
end
rawset(db, 'profile', db.raw.profiles[id])
if db.defaults and db.defaults.profile then
inheritDefaults(db.profile, db.defaults.profile)
end
return db.profile
elseif key == "raw" or key == "defaults" or key == "name" or key == "charName" or key == "namespaces" then
return nil
end
error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2)
end, __newindex = function(db, key, value)
error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2)
end }
local function RecalculateAceDBCopyFromList(target)
local db = target.db
local t = target['acedb-profile-copylist']
for k,v in pairs(t) do
t[k] = nil
end
local _,currentProfile = AceDB.GetProfile(target)
if db and db.raw then
if db.raw.profiles then
for k in pairs(db.raw.profiles) do
if currentProfile ~= k then
if k:find("^char/") then
local name = k:sub(6)
local player, realm = name:match("^(.*) %- (.*)$")
if player then
name = PLAYER_OF_REALM:format(player, realm)
end
t[k] = CHARACTER_COLON .. name
elseif k:find("^realm/") then
local name = k:sub(7)
t[k] = REALM_COLON .. name
elseif k:find("^class/") then
local name = k:sub(7)
t[k] = CLASS_COLON .. name
else
t[k] = k
end
end
end
end
if db.raw.namespaces then
for _,n in pairs(db.raw.namespaces) do
if n.profiles then
for k in pairs(n.profiles) do
if currentProfile ~= k then
if k:find('^char/') then
local name = k:sub(6)
local player, realm = name:match("^(.*) %- (.*)$")
if player then
name = PLAYER_OF_REALM:format(player, realm)
end
t[k] = CHARACTER_COLON .. name
elseif k:find('^realm/') then
local name = k:sub(7)
t[k] = REALM_COLON .. name
elseif k:find('^class/') then
local name = k:sub(7)
t[k] = CLASS_COLON .. name
else
t[k] = k
end
end
end
end
end
end
end
if t.Default then
t.Default = DEFAULT
end
if t.Alternative then
t.Alternative = ALTERNATIVE
end
end
local function RecalculateAceDBProfileList(target)
local t = target['acedb-profile-list']
for k,v in pairs(t) do
t[k] = nil
end
t.char = CHARACTER_COLON .. PLAYER_OF_REALM:format(UnitName("player"), server)
t.realm = REALM_COLON .. realmID
t.class = CLASS_COLON .. classID
t.Default = DEFAULT
local db = target.db
if db and db.raw then
if db.raw.profiles then
for k in pairs(db.raw.profiles) do
if not k:find("^char/") and not k:find("^realm/") and not k:find("^class/") then
t[k] = k
end
end
end
if db.raw.namespaces then
for _,n in pairs(db.raw.namespaces) do
if n.profiles then
for k in pairs(n.profiles) do
if not k:find("^char/") and not k:find("^realm/") and not k:find("^class/") then
t[k] = k
end
end
end
end
end
local curr = db.raw.currentProfile and db.raw.currentProfile[charID]
if curr and not t[curr] then
t[curr] = curr
end
end
if t.Alternative then
t.Alternative = ALTERNATIVE
end
end
local CrawlForSerialization
local CrawlForDeserialization
local function SerializeObject(o)
local t = { o:Serialize() }
CrawlForSerialization(t)
t[0] = o.class:GetLibraryVersion()
return t
end
local function DeserializeObject(t)
CrawlForDeserialization(t)
local className = t[0]
t[0] = nil
return AceLibrary(className):Deserialize(unpack(t))
end
local function IsSerializable(t)
return AceOO.inherits(t, AceOO.Class) and t.class and type(t.class.Deserialize) == "function" and type(t.Serialize) == "function" and type(t.class.GetLibraryVersion) == "function"
end
function CrawlForSerialization(t)
local tmp = new()
for k,v in pairs(t) do
tmp[k] = v
end
for k,v in pairs(tmp) do
if type(v) == "table" and type(rawget(v, 0)) ~= "userdata" then
if IsSerializable(v) then
v = SerializeObject(v)
t[k] = v
else
CrawlForSerialization(v)
end
end
if type(k) == "table" and type(rawget(k, 0)) ~= "userdata" then
if IsSerializable(k) then
t[k] = nil
t[SerializeObject(k)] = v
else
CrawlForSerialization(k)
end
end
tmp[k] = nil
k = nil
end
tmp = del(tmp)
end
local function IsDeserializable(t)
return type(rawget(t, 0)) == "string" and AceLibrary:HasInstance(rawget(t, 0))
end
function CrawlForDeserialization(t)
local tmp = new()
for k,v in pairs(t) do
tmp[k] = v
end
for k,v in pairs(tmp) do
if type(v) == "table" then
if IsDeserializable(v) then
t[k] = DeserializeObject(v)
del(v)
v = t[k]
elseif type(rawget(v, 0)) ~= "userdata" then
CrawlForDeserialization(v)
end
end
if type(k) == "table" then
if IsDeserializable(k) then
t[k] = nil
t[DeserializeObject(k)] = v
del(k)
elseif type(rawget(k, 0)) ~= "userdata" then
CrawlForDeserialization(k)
end
end
tmp[k] = nil
k = nil
end
tmp = del(tmp)
end
local namespace_mt = { __index = function(namespace, key)
local db = namespace.db
local name = namespace.name
if key == "char" then
if db.charName then
if type(_G[db.charName]) ~= "table" then
_G[db.charName] = {}
end
if type(_G[db.charName].namespaces) ~= "table" then
_G[db.charName].namespaces = {}
end
if type(_G[db.charName].namespaces[name]) ~= "table" then
_G[db.charName].namespaces[name] = {}
end
rawset(namespace, 'char', _G[db.charName].namespaces[name])
else
if type(db.raw.namespaces) ~= "table" then
db.raw.namespaces = {}
end
if type(db.raw.namespaces[name]) ~= "table" then
db.raw.namespaces[name] = {}
end
if type(db.raw.namespaces[name].chars) ~= "table" then
db.raw.namespaces[name].chars = {}
end
local id = charID
if type(db.raw.namespaces[name].chars[id]) ~= "table" then
db.raw.namespaces[name].chars[id] = {}
end
rawset(namespace, 'char', db.raw.namespaces[name].chars[id])
end
if namespace.defaults and namespace.defaults.char then
inheritDefaults(namespace.char, namespace.defaults.char)
end
return namespace.char
elseif key == "realm" then
if type(db.raw.namespaces) ~= "table" then
db.raw.namespaces = {}
end
if type(db.raw.namespaces[name]) ~= "table" then
db.raw.namespaces[name] = {}
end
if type(db.raw.namespaces[name].realms) ~= "table" then
db.raw.namespaces[name].realms = {}
end
local id = realmID
if type(db.raw.namespaces[name].realms[id]) ~= "table" then
db.raw.namespaces[name].realms[id] = {}
end
rawset(namespace, 'realm', db.raw.namespaces[name].realms[id])
if namespace.defaults and namespace.defaults.realm then
inheritDefaults(namespace.realm, namespace.defaults.realm)
end
return namespace.realm
elseif key == "server" then
if type(db.raw.namespaces) ~= "table" then
db.raw.namespaces = {}
end
if type(db.raw.namespaces[name]) ~= "table" then
db.raw.namespaces[name] = {}
end
if type(db.raw.namespaces[name].servers) ~= "table" then
db.raw.namespaces[name].servers = {}
end
local id = server
if type(db.raw.namespaces[name].servers[id]) ~= "table" then
db.raw.namespaces[name].servers[id] = {}
end
rawset(namespace, 'server', db.raw.namespaces[name].servers[id])
if namespace.defaults and namespace.defaults.server then
inheritDefaults(namespace.server, namespace.defaults.server)
end
return namespace.server
elseif key == "account" then
if type(db.raw.namespaces) ~= "table" then
db.raw.namespaces = {}
end
if type(db.raw.namespaces[name]) ~= "table" then
db.raw.namespaces[name] = {}
end
if type(db.raw.namespaces[name].account) ~= "table" then
db.raw.namespaces[name].account = {}
end
rawset(namespace, 'account', db.raw.namespaces[name].account)
if namespace.defaults and namespace.defaults.account then
inheritDefaults(namespace.account, namespace.defaults.account)
end
return namespace.account
elseif key == "faction" then
if type(db.raw.namespaces) ~= "table" then
db.raw.namespaces = {}
end
if type(db.raw.namespaces[name]) ~= "table" then
db.raw.namespaces[name] = {}
end
if type(db.raw.namespaces[name].factions) ~= "table" then
db.raw.namespaces[name].factions = {}
end
local id = faction
if type(db.raw.namespaces[name].factions[id]) ~= "table" then
db.raw.namespaces[name].factions[id] = {}
end
rawset(namespace, 'faction', db.raw.namespaces[name].factions[id])
if namespace.defaults and namespace.defaults.faction then
inheritDefaults(namespace.faction, namespace.defaults.faction)
end
return namespace.faction
elseif key == "class" then
if type(db.raw.namespaces) ~= "table" then
db.raw.namespaces = {}
end
if type(db.raw.namespaces[name]) ~= "table" then
db.raw.namespaces[name] = {}
end
if type(db.raw.namespaces[name].classes) ~= "table" then
db.raw.namespaces[name].classes = {}
end
local id = classID
if type(db.raw.namespaces[name].classes[id]) ~= "table" then
db.raw.namespaces[name].classes[id] = {}
end
rawset(namespace, 'class', db.raw.namespaces[name].classes[id])
if namespace.defaults and namespace.defaults.class then
inheritDefaults(namespace.class, namespace.defaults.class)
end
return namespace.class
elseif key == "profile" then
if type(db.raw.namespaces) ~= "table" then
db.raw.namespaces = {}
end
if type(db.raw.namespaces[name]) ~= "table" then
db.raw.namespaces[name] = {}
end
if type(db.raw.namespaces[name].profiles) ~= "table" then
db.raw.namespaces[name].profiles = setmetatable({}, caseInsensitive_mt)
else
setmetatable(db.raw.namespaces[name].profiles, caseInsensitive_mt)
end
local id = db.raw.currentProfile[charID]
if id == "char" then
id = "char/" .. charID
elseif id == "class" then
id = "class/" .. classID
elseif id == "realm" then
id = "realm/" .. realmID
end
if type(db.raw.namespaces[name].profiles[id]) ~= "table" then
db.raw.namespaces[name].profiles[id] = {}
end
rawset(namespace, 'profile', db.raw.namespaces[name].profiles[id])
if namespace.defaults and namespace.defaults.profile then
inheritDefaults(namespace.profile, namespace.defaults.profile)
end
return namespace.profile
elseif key == "defaults" or key == "name" or key == "db" then
return nil
end
error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2)
end, __newindex = function(db, key, value)
error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2)
end }
local tmp = {}
function AceDB:InitializeDB(addonName)
local db = self.db
if not db then
if addonName then
AceDB.addonsLoaded[addonName] = true
end
return
end
if db.raw then
-- someone manually initialized
return
end
if type(_G[db.name]) ~= "table" then
_G[db.name] = {}
else
CrawlForDeserialization(_G[db.name])
end
if db.charName then
if type(_G[db.charName]) ~= "table" then
_G[db.charName] = {}
else
CrawlForDeserialization(_G[db.charName])
end
end
rawset(db, 'raw', _G[db.name])
if not db.raw.currentProfile then
db.raw.currentProfile = {}
else
for k,v in pairs(db.raw.currentProfile) do
tmp[convertFromOldCharID(k)] = v
db.raw.currentProfile[k] = nil
end
for k,v in pairs(tmp) do
db.raw.currentProfile[k] = v
tmp[k] = nil
end
end
if not db.raw.currentProfile[charID] then
db.raw.currentProfile[charID] = AceDB.registry[self] or "Default"
end
if db.raw.profiles then
for k,v in pairs(db.raw.profiles) do
local new_k = k
if k:find("^char/") then
new_k = "char/" .. convertFromOldCharID(k:sub(6))
end
tmp[new_k] = v
db.raw.profiles[k] = nil
end
for k,v in pairs(tmp) do
db.raw.profiles[k] = v
tmp[k] = nil
end
end
if db.raw.disabledModules then -- AceModuleCore-2.0
for k,v in pairs(db.raw.disabledModules) do
local new_k = k
if k:find("^char/") then
new_k = "char/" .. convertFromOldCharID(k:sub(6))
end
tmp[new_k] = v
db.raw.disabledModules[k] = nil
end
for k,v in pairs(tmp) do
db.raw.disabledModules[k] = v
tmp[k] = nil
end
end
if db.raw.chars then
for k,v in pairs(db.raw.chars) do
tmp[convertFromOldCharID(k)] = v
db.raw.chars[k] = nil
end
for k,v in pairs(tmp) do
db.raw.chars[k] = v
tmp[k] = nil
end
end
if db.raw.namespaces then
for l,u in pairs(db.raw.namespaces) do
if u.chars then
for k,v in pairs(u.chars) do
tmp[convertFromOldCharID(k)] = v
u.chars[k] = nil
end
for k,v in pairs(tmp) do
u.chars[k] = v
tmp[k] = nil
end
end
end
end
if db.raw.disabled then
setmetatable(db.raw.disabled, caseInsensitive_mt)
end
if self['acedb-profile-copylist'] then
RecalculateAceDBCopyFromList(self)
end
if self['acedb-profile-list'] then
RecalculateAceDBProfileList(self)
end
setmetatable(db, db_mt)
end
function AceDB:OnEmbedInitialize(target, name)
if name then
self:ADDON_LOADED(name)
end
self.InitializeDB(target, name)
end
function AceDB:RegisterDB(name, charName, defaultProfile)
AceDB:argCheck(name, 2, "string")
AceDB:argCheck(charName, 3, "string", "nil")
AceDB:argCheck(defaultProfile, 4, "string", "nil")
if self.db then
AceDB:error("Cannot call \"RegisterDB\" if self.db is set.")
end
local stack = debugstack()
local addonName = stack:gsub(".-\n.-\\AddOns\\(.-)\\.*", "%1")
self.db = {
name = name,
charName = charName
}
AceDB.registry[self] = defaultProfile or "Default"
if AceDB.addonsLoaded[addonName] then
AceDB.InitializeDB(self, addonName)
else
AceDB.addonsToBeInitialized[self] = addonName
end
end
function AceDB:RegisterDefaults(kind, defaults, a3)
local name
if a3 then
name, kind, defaults = kind, defaults, a3
AceDB:argCheck(name, 2, "string")
AceDB:argCheck(kind, 3, "string")
AceDB:argCheck(defaults, 4, "table")
else
AceDB:argCheck(kind, 2, "string")
AceDB:argCheck(defaults, 3, "table")
end
if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" and kind ~= "faction" and kind ~= "server" then
AceDB:error("Bad argument #%d to `RegisterDefaults' (\"char\", \"class\", \"profile\", \"account\", \"realm\", \"server\", or \"faction\" expected, got %q)", a3 and 3 or 2, kind)
end
if type(self.db) ~= "table" or type(self.db.name) ~= "string" then
AceDB:error("Cannot call \"RegisterDefaults\" unless \"RegisterDB\" has been previously called.")
end
local db
if name then
local namespace = self:AcquireDBNamespace(name)
if namespace.defaults and namespace.defaults[kind] then
AceDB:error("\"RegisterDefaults\" has already been called for %q::%q.", name, kind)
end
db = namespace
else
if self.db.defaults and self.db.defaults[kind] then
AceDB:error("\"RegisterDefaults\" has already been called for %q.", kind)
end
db = self.db
end
if not db.defaults then
rawset(db, 'defaults', {})
end
db.defaults[kind] = defaults
if rawget(db, kind) then
inheritDefaults(db[kind], defaults)
end
end
function AceDB:ResetDB(kind, a2)
local name
if a2 then
name, kind = kind, a2
AceDB:argCheck(name, 2, "nil", "string")
AceDB:argCheck(kind, 3, "nil", "string")
else
AceDB:argCheck(kind, 2, "nil", "string")
if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" and kind ~= "faction" and kind ~= "server" then
name, kind = kind, nil
end
end
if not self.db or not self.db.raw then
AceDB:error("Cannot call \"ResetDB\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
end
local db = self.db
if not kind then
if not name then
if db.charName then
_G[db.charName] = nil
end
_G[db.name] = nil
rawset(db, 'raw', nil)
AceDB.InitializeDB(self)
if db.namespaces then
for name,v in pairs(db.namespaces) do
rawset(v, 'account', nil)
rawset(v, 'char', nil)
rawset(v, 'class', nil)
rawset(v, 'profile', nil)
rawset(v, 'realm', nil)
rawset(v, 'server', nil)
rawset(v, 'faction', nil)
end
end
else
if db.raw.namespaces then
db.raw.namespaces[name] = nil
end
if db.namespaces then
local v = db.namespaces[name]
if v then
rawset(v, 'account', nil)
rawset(v, 'char', nil)
rawset(v, 'class', nil)
rawset(v, 'profile', nil)
rawset(v, 'realm', nil)
rawset(v, 'server', nil)
rawset(v, 'faction', nil)
end
end
end
elseif kind == "account" then
if name then
db.raw.account = nil
rawset(db, 'account', nil)
if db.raw.namespaces then
for name,v in pairs(db.raw.namespaces) do
v.account = nil
end
end
if db.namespaces then
for name,v in pairs(db.namespaces) do
rawset(v, 'account', nil)
end
end
else
if db.raw.namespaces and db.raw.namespaces[name] then
db.raw.namespaces[name].account = nil
end
if db.namespaces then
local v = db.namespaces[name]
if v then
rawset(v, 'account', nil)
end
end
end
elseif kind == "char" then
if name then
if db.charName then
_G[db.charName] = nil
else
if db.raw.chars then
db.raw.chars[charID] = nil
end
if db.raw.namespaces then
for name,v in pairs(db.raw.namespaces) do
if v.chars then
v.chars[charID] = nil
end
end
end
end
rawset(db, 'char', nil)
if db.namespaces then
for name,v in pairs(db.namespaces) do
rawset(v, 'char', nil)
end
end
else
if db.charName then
local x = _G[db.charName]
if x.namespaces then
x.namespaces[name] = nil
end
else
if db.raw.namespaces then
local v = db.namespaces[name]
if v and v.chars then
v.chars[charID] = nil
end
end
end
if db.namespaces then
local v = db.namespaces[name]
if v then
rawset(v, 'char', nil)
end
end
end
elseif kind == "realm" then
if not name then
if db.raw.realms then
db.raw.realms[realmID] = nil
end
rawset(db, 'realm', nil)
if db.raw.namespaces then
for name,v in pairs(db.raw.namespaces) do
if v.realms then
v.realms[realmID] = nil
end
end
end
if db.namespaces then
for name,v in pairs(db.namespaces) do
rawset(v, 'realm', nil)
end
end
else
if db.raw.namespaces then
local v = db.raw.namespaces[name]
if v and v.realms then
v.realms[realmID] = nil
end
end
if db.namespaces then
local v = db.namespaces[name]
if v then
rawset(v, 'realm', nil)
end
end
end
elseif kind == "server" then
if not name then
if db.raw.servers then
db.raw.servers[server] = nil
end
rawset(db, 'server', nil)
if db.raw.namespaces then
for name,v in pairs(db.raw.namespaces) do
if v.servers then
v.servers[server] = nil
end
end
end
if db.namespaces then
for name,v in pairs(db.namespaces) do
rawset(v, 'server', nil)
end
end
else
if db.raw.namespaces then
local v = db.raw.namespaces[name]
if v and v.servers then
v.servers[server] = nil
end
end
if db.namespaces then
local v = db.namespaces[name]
if v then
rawset(v, 'server', nil)
end
end
end
elseif kind == "faction" then
if not name then
if db.raw.factions then
db.raw.factions[faction] = nil
end
rawset(db, 'faction', nil)
if db.raw.namespaces then
for name,v in pairs(db.raw.namespaces) do
if v.factions then
v.factions[faction] = nil
end
end
end
if db.namespaces then
for name,v in pairs(db.namespaces) do
rawset(v, 'faction', nil)
end
end
else
if db.raw.namespaces then
local v = db.raw.namespaces[name]
if v and v.factions then
v.factions[faction] = nil
end
end
if db.namespaces then
local v = db.namespaces[name]
if v then
rawset(v, 'faction', nil)
end
end
end
elseif kind == "class" then
if not name then
if db.raw.realms then
db.raw.realms[classID] = nil
end
rawset(db, 'class', nil)
if db.raw.namespaces then
for name,v in pairs(db.raw.namespaces) do
if v.classes then
v.classes[classID] = nil
end
end
end
if db.namespaces then
for name,v in pairs(db.namespaces) do
rawset(v, 'class', nil)
end
end
else
if db.raw.namespaces then
local v = db.raw.namespaces[name]
if v and v.classes then
v.classes[classID] = nil
end
end
if db.namespaces then
local v = db.namespaces[name]
if v then
rawset(v, 'class', nil)
end
end
end
elseif kind == "profile" then
local id = db.raw.currentProfile and db.raw.currentProfile[charID] or AceDB.registry[self] or "Default"
if id == "char" then
id = "char/" .. charID
elseif id == "class" then
id = "class/" .. classID
elseif id == "realm" then
id = "realm/" .. realmID
end
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedProfileDisable) == "function" then
safecall(mixin.OnEmbedProfileDisable, mixin, self, id)
end
end
end
current = current.super
end
if type(self.OnProfileDisable) == "function" then
safecall(self.OnProfileDisable, self, id)
end
local active = self:IsActive()
if not name then
if db.raw.profiles then
db.raw.profiles[id] = nil
end
rawset(db, 'profile', nil)
if db.raw.namespaces then
for name,v in pairs(db.raw.namespaces) do
if v.profiles then
v.profiles[id] = nil
end
end
end
if db.namespaces then
for name,v in pairs(db.namespaces) do
rawset(v, 'profile', nil)
end
end
else
if db.raw.namespaces then
local v = db.raw.namespaces[name]
if v and v.profiles then
v.profiles[id] = nil
end
end
if db.namespaces then
local v = db.namespaces[name]
if v then
rawset(v, 'profile', nil)
end
end
end
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedProfileEnable) == "function" then
safecall(mixin.OnEmbedProfileEnable, mixin, self, id)
end
end
end
current = current.super
end
if type(self.OnProfileEnable) == "function" then
safecall(self.OnProfileEnable, self, id)
end
local newactive = self:IsActive()
if active ~= newactive then
if newactive then
local first = nil
if AceOO.inherits(self, "AceAddon-2.0") then
local AceAddon = AceLibrary("AceAddon-2.0")
if not AceAddon.addonsStarted[self] then
return
end
if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[self] then
AceAddon.addonsEnabled[self] = true
first = true
end
end
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedEnable) == "function" then
safecall(mixin.OnEmbedEnable, mixin, self, first)
end
end
end
current = current.super
end
if type(self.OnEnable) == "function" then
safecall(self.OnEnable, self, first)
end
if AceEvent then
AceEvent:TriggerEvent("Ace2_AddonEnabled", self, first)
end
else
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedDisable) == "function" then
safecall(mixin.OnEmbedDisable, mixin, self)
end
end
end
current = current.super
end
if type(self.OnDisable) == "function" then
safecall(self.OnDisable, self)
end
if AceEvent then
AceEvent:TriggerEvent("Ace2_AddonDisabled", self)
end
end
end
else
return -- skip event
end
if AceEvent then
AceEvent:TriggerEvent("AceDB20_ResetDB", self, self.db.name, kind)
end
end
local function cleanDefaults(t, defaults, blocker)
if defaults then
for k,v in pairs(t) do
if (not blocker or (blocker[k] == nil and blocker['*'] == nil and blocker['**'] == nil)) and (defaults[k] ~= nil or defaults['*'] ~= nil or defaults['**'] ~= nil) then
local u = defaults[k]
if u == nil then
u = defaults['*']
if u == nil then
u = defaults['**']
end
end
if v == u then
t[k] = nil
elseif type(v) == "table" and type(u) == "table" then
if cleanDefaults(v, u) then
t[k] = nil
else
local w = defaults['**']
if w ~= u then
if cleanDefaults(v, w, u) then
t[k] = nil
end
end
end
end
end
end
end
return t and next(t) == nil
end
function AceDB:GetProfile()
if not self.db or not self.db.raw then
return nil
end
if not self.db.raw.currentProfile then
self.db.raw.currentProfile = {}
end
if not self.db.raw.currentProfile[charID] then
self.db.raw.currentProfile[charID] = AceDB.registry[self] or "Default"
end
local profile = self.db.raw.currentProfile[charID]
if profile == "char" then
return "char", "char/" .. charID
elseif profile == "class" then
return "class", "class/" .. classID
elseif profile == "realm" then
return "realm", "realm/" .. realmID
end
return profile, profile
end
local function copyTable(to, from)
setmetatable(to, nil)
for k,v in pairs(from) do
if type(k) == "table" then
k = copyTable({}, k)
end
if type(v) == "table" then
v = copyTable({}, v)
end
to[k] = v
end
setmetatable(to, from)
return to
end
function AceDB:SetProfile(name)
AceDB:argCheck(name, 2, "string")
if not self.db or not self.db.raw then
AceDB:error("Cannot call \"SetProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
end
local db = self.db
local lowerName = name:lower()
if lowerName:find("^char/") or lowerName:find("^realm/") or lowerName:find("^class/") then
if lowerName:find("^char/") then
name = "char"
else
name = lowerName:sub(1, 5)
end
lowerName = name:lower()
end
local oldName = db.raw.currentProfile[charID]
if oldName:lower() == name:lower() then
return
end
local oldProfileData = db.profile
local realName = name
if lowerName == "char" then
realName = name .. "/" .. charID
elseif lowerName == "realm" then
realName = name .. "/" .. realmID
elseif lowerName == "class" then
realName = name .. "/" .. classID
end
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedProfileDisable) == "function" then
safecall(mixin.OnEmbedProfileDisable, mixin, self, realName)
end
end
end
current = current.super
end
if type(self.OnProfileDisable) == "function" then
safecall(self.OnProfileDisable, self, realName)
end
local active = self:IsActive()
db.raw.currentProfile[charID] = name
rawset(db, 'profile', nil)
if db.namespaces then
for k,v in pairs(db.namespaces) do
rawset(v, 'profile', nil)
end
end
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedProfileEnable) == "function" then
safecall(mixin.OnEmbedProfileEnable, mixin, self, oldName, oldProfileData)
end
end
end
current = current.super
end
if type(self.OnProfileEnable) == "function" then
safecall(self.OnProfileEnable, self, oldName, oldProfileData)
end
if cleanDefaults(oldProfileData, db.defaults and db.defaults.profile) then
db.raw.profiles[oldName] = nil
if not next(db.raw.profiles) then
db.raw.profiles = nil
end
end
local newactive = self:IsActive()
if active ~= newactive then
local first = nil
if AceOO.inherits(self, "AceAddon-2.0") then
local AceAddon = AceLibrary("AceAddon-2.0")
if not AceAddon.addonsStarted[self] then
return
end
if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[self] then
first = true
end
end
if newactive then
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedEnable) == "function" then
safecall(mixin.OnEmbedEnable, mixin, self, first)
end
end
end
current = current.super
end
if type(self.OnEnable) == "function" then
safecall(self.OnEnable, self, first)
end
if AceEvent then
AceEvent:TriggerEvent("Ace2_AddonEnabled", self, first)
end
else
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedDisable) == "function" then
safecall(mixin.OnEmbedDisable, mixin, self)
end
end
end
current = current.super
end
if type(self.OnDisable) == "function" then
safecall(self.OnDisable, self)
end
if AceEvent then
AceEvent:TriggerEvent("Ace2_AddonDisabled", self)
end
end
end
if self['acedb-profile-list'] then
RecalculateAceDBProfileList(self)
end
if self['acedb-profile-copylist'] then
RecalculateAceDBCopyFromList(self)
end
if Dewdrop then
Dewdrop:Refresh()
end
end
function AceDB:CopyProfileFrom(copyFrom)
AceDB:argCheck(copyFrom, 2, "string")
if not self.db or not self.db.raw then
AceDB:error("Cannot call \"CopyProfileFrom\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
end
local db = self.db
local lowerCopyFrom = copyFrom:lower()
if not db.raw.profiles or not db.raw.profiles[copyFrom] then
local good = false
if db.raw.namespaces then
for _,n in pairs(db.raw.namespaces) do
if n.profiles and n.profiles[copyFrom] then
good = true
break
end
end
end
if not good then
AceDB:error("Cannot copy from profile %q, it does not exist.", copyFrom)
end
end
local currentProfile = db.raw.currentProfile[charID]
if currentProfile:lower() == lowerCopyFrom then
AceDB:error("Cannot copy from profile %q, it is currently in use.", copyFrom)
end
local oldProfileData = db.profile
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedProfileDisable) == "function" then
safecall(mixin.OnEmbedProfileDisable, mixin, self, currentProfile)
end
end
end
current = current.super
end
if type(self.OnProfileDisable) == "function" then
safecall(self.OnProfileDisable, self, realName)
end
local active = self:IsActive()
for k,v in pairs(db.profile) do
db.profile[k] = nil
end
if db.raw.profiles[copyFrom] then
copyTable(db.profile, db.raw.profiles[copyFrom])
end
inheritDefaults(db.profile, db.defaults and db.defaults.profile)
if db.namespaces then
for l,u in pairs(db.namespaces) do
for k,v in pairs(u.profile) do
u.profile[k] = nil
end
if db.raw.namespaces[l].profiles[copyFrom] then
copyTable(u.profile, db.raw.namespaces[l].profiles[copyFrom])
end
inheritDefaults(u.profile, u.defaults and u.defaults.profile)
end
end
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedProfileEnable) == "function" then
safecall(mixin.OnEmbedProfileEnable, mixin, self, copyFrom, oldProfileData, copyFrom)
end
end
end
current = current.super
end
if type(self.OnProfileEnable) == "function" then
safecall(self.OnProfileEnable, self, copyFrom, oldProfileData, copyFrom)
end
local newactive = self:IsActive()
if active ~= newactive then
if AceOO.inherits(self, "AceAddon-2.0") then
local AceAddon = AceLibrary("AceAddon-2.0")
if not AceAddon.addonsStarted[self] then
return
end
end
if newactive then
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedEnable) == "function" then
safecall(mixin.OnEmbedEnable, mixin, self)
end
end
end
current = current.super
end
if type(self.OnEnable) == "function" then
safecall(self.OnEnable, self)
end
if AceEvent then
AceEvent:TriggerEvent("Ace2_AddonEnabled", self)
end
else
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedDisable) == "function" then
safecall(mixin.OnEmbedDisable, mixin, self)
end
end
end
current = current.super
end
if type(self.OnDisable) == "function" then
safecall(self.OnDisable, self)
end
if AceEvent then
AceEvent:TriggerEvent("Ace2_AddonDisabled", self)
end
end
end
if self['acedb-profile-list'] then
RecalculateAceDBProfileList(self)
end
if self['acedb-profile-copylist'] then
RecalculateAceDBCopyFromList(self)
end
if Dewdrop then
Dewdrop:Refresh()
end
end
function AceDB:DeleteProfile(profile, noconfirm)
AceDB:argCheck(profile , 2, "string")
if not self.db or not self.db.raw then
AceDB:error("Cannot call \"DeleteProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
end
local db = self.db
local currentProfile = db.raw.currentProfile[charID]
if currentProfile:lower() == profile:lower() then
AceDB:error("Cannot delete profile %q, it is currently in use.", profile)
end
if not (noconfirm or IsShiftKeyDown()) then
if not StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] then
StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] = {}
end
local t = StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"]
t.text = format("%s: %s?", DELETE_PROFILE, profile)
t.button1 = DELETE_PROFILE
t.button2 = CANCEL or "Cancel"
t.OnAccept = function()
self:DeleteProfile(profile, true)
end
t.timeout = 0
t.whileDead = 1
t.hideOnEscape = 1
StaticPopup_Show("ACEDB20_CONFIRM_DELETE_DIALOG")
return;
end
local good = false
if db.raw.profiles and db.raw.profiles[profile] then
good = true;
db.raw.profiles[profile] = nil;
end
if db.raw.namespaces then
for _,n in pairs(db.raw.namespaces) do
if n.profiles and n.profiles[profile] then
n.profiles[profile] = nil;
good = true
end
end
end
if not good then
AceDB:error("Cannot delete profile %q, it does not exist.", profile)
end
if self['acedb-profile-list'] then
RecalculateAceDBProfileList(self)
end
if self['acedb-profile-copylist'] then
RecalculateAceDBCopyFromList(self)
end
if Dewdrop then
Dewdrop:Refresh()
end
end
function AceDB:IsActive()
return not self.db or not self.db.raw or not self.db.raw.disabled or not self.db.raw.disabled[self.db.raw.currentProfile[charID]]
end
function AceDB:ToggleActive(state)
AceDB:argCheck(state, 2, "boolean", "nil")
if not self.db or not self.db.raw then
AceDB:error("Cannot call \"ToggleActive\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.")
end
local db = self.db
if not db.raw.disabled then
db.raw.disabled = setmetatable({}, caseInsensitive_mt)
end
local profile = db.raw.currentProfile[charID]
local disable
if state == nil then
disable = not db.raw.disabled[profile]
else
disable = not state
if disable == db.raw.disabled[profile] then
return
end
end
db.raw.disabled[profile] = disable or nil
if AceOO.inherits(self, "AceAddon-2.0") then
local AceAddon = AceLibrary("AceAddon-2.0")
if not AceAddon.addonsStarted[self] then
return
end
end
if not disable then
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedEnable) == "function" then
safecall(mixin.OnEmbedEnable, mixin, self)
end
end
end
current = current.super
end
if type(self.OnEnable) == "function" then
safecall(self.OnEnable, self)
end
if AceEvent then
AceEvent:TriggerEvent("Ace2_AddonEnabled", self)
end
else
local current = self.class
while current and current ~= AceOO.Class do
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedDisable) == "function" then
safecall(mixin.OnEmbedDisable, mixin, self)
end
end
end
current = current.super
end
if type(self.OnDisable) == "function" then
safecall(self.OnDisable, self)
end
if AceEvent then
AceEvent:TriggerEvent("Ace2_AddonDisabled", self)
end
end
return not disable
end
function AceDB:embed(target)
self.super.embed(self, target)
if not AceEvent then
AceDB:error(MAJOR_VERSION .. " requires AceEvent-2.0")
end
end
function AceDB:ADDON_LOADED(name)
AceDB.addonsLoaded[name] = true
for addon, addonName in pairs(AceDB.addonsToBeInitialized) do
if name == addonName then
AceDB.InitializeDB(addon, name)
AceDB.addonsToBeInitialized[addon] = nil
end
end
end
function AceDB:PLAYER_LOGOUT()
for addon, defaultProfile in pairs(AceDB.registry) do
local db = addon.db
if db then
if type(addon.OnDatabaseCleanup) == "function" then
safecall(addon.OnDatabaseCleanup, addon)
end
setmetatable(db, nil)
CrawlForSerialization(db.raw)
if type(_G[db.charName]) == "table" then
CrawlForSerialization(_G[db.charName])
end
if db.char and cleanDefaults(db.char, db.defaults and db.defaults.char) then
if db.charName and _G[db.charName] and _G[db.charName].global == db.char then
_G[db.charName].global = nil
if not next(_G[db.charName]) then
_G[db.charName] = nil
end
else
if db.raw.chars then
db.raw.chars[charID] = nil
if not next(db.raw.chars) then
db.raw.chars = nil
end
end
end
end
if db.realm and cleanDefaults(db.realm, db.defaults and db.defaults.realm) then
if db.raw.realms then
db.raw.realms[realmID] = nil
if not next(db.raw.realms) then
db.raw.realms = nil
end
end
end
if db.server and cleanDefaults(db.server, db.defaults and db.defaults.server) then
if db.raw.servers then
db.raw.servers[server] = nil
if not next(db.raw.servers) then
db.raw.servers = nil
end
end
end
if db.faction and cleanDefaults(db.faction, db.defaults and db.defaults.faction) then
if db.raw.factions then
db.raw.factions[faction] = nil
if not next(db.raw.factions) then
db.raw.factions = nil
end
end
end
if db.class and cleanDefaults(db.class, db.defaults and db.defaults.class) then
if db.raw.classes then
db.raw.classes[classID] = nil
if not next(db.raw.classes) then
db.raw.classes = nil
end
end
end
if db.account and cleanDefaults(db.account, db.defaults and db.defaults.account) then
db.raw.account = nil
end
if db.profile and cleanDefaults(db.profile, db.defaults and db.defaults.profile) then
if db.raw.profiles then
db.raw.profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or defaultProfile or "Default"] = nil
if not next(db.raw.profiles) then
db.raw.profiles = nil
end
end
end
if db.namespaces and db.raw.namespaces then
for name,v in pairs(db.namespaces) do
if db.raw.namespaces[name] then
setmetatable(v, nil)
if v.char and cleanDefaults(v.char, v.defaults and v.defaults.char) then
if db.charName and _G[db.charName] and _G[db.charName].namespaces and _G[db.charName].namespaces[name] == v then
_G[db.charName].namespaces[name] = nil
if not next(_G[db.charName].namespaces) then
_G[db.charName].namespaces = nil
if not next(_G[db.charName]) then
_G[db.charName] = nil
end
end
else
if db.raw.namespaces[name].chars then
db.raw.namespaces[name].chars[charID] = nil
if not next(db.raw.namespaces[name].chars) then
db.raw.namespaces[name].chars = nil
end
end
end
end
if v.realm and cleanDefaults(v.realm, v.defaults and v.defaults.realm) then
if db.raw.namespaces[name].realms then
db.raw.namespaces[name].realms[realmID] = nil
if not next(db.raw.namespaces[name].realms) then
db.raw.namespaces[name].realms = nil
end
end
end
if v.server and cleanDefaults(v.server, v.defaults and v.defaults.server) then
if db.raw.namespaces[name].servers then
db.raw.namespaces[name].servers[server] = nil
if not next(db.raw.namespaces[name].servers) then
db.raw.namespaces[name].servers = nil
end
end
end
if v.faction and cleanDefaults(v.faction, v.defaults and v.defaults.faction) then
if db.raw.namespaces[name].factions then
db.raw.namespaces[name].factions[faction] = nil
if not next(db.raw.namespaces[name].factions) then
db.raw.namespaces[name].factions = nil
end
end
end
if v.class and cleanDefaults(v.class, v.defaults and v.defaults.class) then
if db.raw.namespaces[name].classes then
db.raw.namespaces[name].classes[classID] = nil
if not next(db.raw.namespaces[name].classes) then
db.raw.namespaces[name].classes = nil
end
end
end
if v.account and cleanDefaults(v.account, v.defaults and v.defaults.account) then
db.raw.namespaces[name].account = nil
end
if v.profile and cleanDefaults(v.profile, v.defaults and v.defaults.profile) then
if db.raw.namespaces[name].profiles then
db.raw.namespaces[name].profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or defaultProfile or "Default"] = nil
if not next(db.raw.namespaces[name].profiles) then
db.raw.namespaces[name].profiles = nil
end
end
end
if not next(db.raw.namespaces[name]) then
db.raw.namespaces[name] = nil
end
end
end
if not next(db.raw.namespaces) then
db.raw.namespaces = nil
end
end
if db.raw.disabled and not next(db.raw.disabled) then
db.raw.disabled = nil
end
if db.raw.currentProfile then
for k,v in pairs(db.raw.currentProfile) do
if v:lower() == (defaultProfile or "Default"):lower() then
db.raw.currentProfile[k] = nil
end
end
if not next(db.raw.currentProfile) then
db.raw.currentProfile = nil
end
end
if _G[db.name] and not next(_G[db.name]) then
_G[db.name] = nil
end
end
end
end
function AceDB:AcquireDBNamespace(name)
AceDB:argCheck(name, 2, "string")
local db = self.db
if not db then
AceDB:error("Cannot call `AcquireDBNamespace' before `RegisterDB' has been called.", 2)
end
if not db.namespaces then
rawset(db, 'namespaces', {})
end
if not db.namespaces[name] then
local namespace = {}
db.namespaces[name] = namespace
namespace.db = db
namespace.name = name
setmetatable(namespace, namespace_mt)
end
return db.namespaces[name]
end
function AceDB:GetAceOptionsDataTable(target)
if not target['acedb-profile-list'] then
target['acedb-profile-list'] = setmetatable({}, caseInsensitive_mt)
RecalculateAceDBProfileList(target)
end
if not target['acedb-profile-copylist'] then
target['acedb-profile-copylist'] = setmetatable({}, caseInsensitive_mt)
RecalculateAceDBCopyFromList(target)
end
return {
standby = {
cmdName = STATE,
guiName = ENABLED,
name = ACTIVE,
desc = TOGGLE_ACTIVE,
type = "toggle",
get = "IsActive",
set = "ToggleActive",
map = MAP_ACTIVESUSPENDED,
order = -3,
},
profile = {
type = 'group',
name = PROFILE,
desc = SET_PROFILE,
order = -3.5,
get = "GetProfile",
args = {
choose = {
guiName = CHOOSE_PROFILE_GUI,
cmdName = PROFILE,
desc = CHOOSE_PROFILE_DESC,
type = 'text',
get = "GetProfile",
set = "SetProfile",
validate = target['acedb-profile-list']
},
copy = {
guiName = COPY_PROFILE_GUI,
cmdName = PROFILE,
desc = COPY_PROFILE_DESC,
type = 'text',
get = false,
set = "CopyProfileFrom",
validate = target['acedb-profile-copylist'],
disabled = function()
return not next(target['acedb-profile-copylist'])
end,
},
other = {
guiName = OTHER_PROFILE_GUI,
cmdName = PROFILE,
desc = OTHER_PROFILE_DESC,
usage = OTHER_PROFILE_USAGE,
type = 'text',
get = "GetProfile",
set = "SetProfile",
},
delete = {
name = DELETE_PROFILE,
desc = DELETE_PROFILE_DESC,
usage = DELETE_PROFILE_USAGE,
type = 'text',
set = "DeleteProfile",
get = false,
validate = target['acedb-profile-copylist'],
disabled = function()
return not next(target['acedb-profile-copylist'])
end,
},
reset = {
name = RESET_PROFILE,
desc = RESET_PROFILE_DESC,
type = 'execute',
func = function()
target:ResetDB('profile')
end,
confirm = true,
}
}
},
}
end
local function activate(self, oldLib, oldDeactivate)
AceDB = self
AceEvent = AceLibrary:HasInstance("AceEvent-2.0") and AceLibrary("AceEvent-2.0")
self.addonsToBeInitialized = oldLib and oldLib.addonsToBeInitialized or {}
self.addonsLoaded = oldLib and oldLib.addonsLoaded or {}
self.registry = oldLib and oldLib.registry or {}
for k, v in pairs(self.registry) do
if v == true then
self.registry[k] = "Default"
end
end
self:activate(oldLib, oldDeactivate)
for t in pairs(self.embedList) do
if t.db then
rawset(t.db, 'char', nil)
rawset(t.db, 'realm', nil)
rawset(t.db, 'class', nil)
rawset(t.db, 'account', nil)
rawset(t.db, 'server', nil)
rawset(t.db, 'faction', nil)
rawset(t.db, 'profile', nil)
setmetatable(t.db, db_mt)
end
end
if oldLib then
oldDeactivate(oldLib)
end
end
local function external(self, major, instance)
if major == "AceEvent-2.0" then
AceEvent = instance
AceEvent:embed(self)
self:RegisterEvent("ADDON_LOADED")
self:RegisterEvent("PLAYER_LOGOUT")
elseif major == "Dewdrop-2.0" then
Dewdrop = instance
end
end
AceLibrary:Register(AceDB, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
AceDB = AceLibrary(MAJOR_VERSION)