From 8bd1e2bc83c222f02f4d69173c6a8b2b28272944 Mon Sep 17 00:00:00 2001
From: RBG DEV <149433862+rbgdevx@users.noreply.github.com>
Date: Mon, 2 Sep 2024 23:42:35 -0400
Subject: [PATCH] refactor
---
.vscode/settings.json | 24 +-
AutoBodyRes.lua | 58 +-
AutoBodyRes.toc | 9 +-
CHANGELOG.md | 7 +
Libs/AceAddon-3.0/AceAddon-3.0.lua | 649 ---------------
Libs/AceAddon-3.0/AceAddon-3.0.xml | 4 -
Libs/AceConfig-3.0/AceConfig-3.0.lua | 4 +-
Libs/AceConsole-3.0/AceConsole-3.0.lua | 246 ------
Libs/AceConsole-3.0/AceConsole-3.0.xml | 4 -
Libs/AceDB-3.0/AceDB-3.0.lua | 740 ------------------
Libs/AceDB-3.0/AceDB-3.0.xml | 4 -
Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua | 456 -----------
Libs/AceEvent-3.0/AceEvent-3.0.lua | 126 ---
Libs/AceEvent-3.0/AceEvent-3.0.xml | 4 -
.../widgets/AceGUIWidget-ColorPicker.lua | 92 ++-
.../widgets/AceGUIWidget-EditBox.lua | 12 +-
.../widgets/AceGUIWidget-MultiLineEditBox.lua | 12 +-
.../LibSharedMedia-3.0/LibSharedMedia-3.0.lua | 10 +-
README.md | 2 +
config.lua | 86 +-
embeds.xml | 15 +-
helpers.lua | 139 +++-
interface.lua | 35 +-
libs/LibChangelog/CHANGELOG.md | 8 +
libs/LibChangelog/LibChangelog.lua | 187 +++++
libs/LibChangelog/LibChangelog.toc | 8 +
.../LibChangelog/LibChangelog.xml | 2 +-
libs/LibChangelog/README.md | 3 +
options.lua | 142 +++-
29 files changed, 699 insertions(+), 2389 deletions(-)
delete mode 100644 Libs/AceAddon-3.0/AceAddon-3.0.lua
delete mode 100644 Libs/AceAddon-3.0/AceAddon-3.0.xml
delete mode 100644 Libs/AceConsole-3.0/AceConsole-3.0.lua
delete mode 100644 Libs/AceConsole-3.0/AceConsole-3.0.xml
delete mode 100644 Libs/AceDB-3.0/AceDB-3.0.lua
delete mode 100644 Libs/AceDB-3.0/AceDB-3.0.xml
delete mode 100644 Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua
delete mode 100644 Libs/AceEvent-3.0/AceEvent-3.0.lua
delete mode 100644 Libs/AceEvent-3.0/AceEvent-3.0.xml
create mode 100644 libs/LibChangelog/CHANGELOG.md
create mode 100644 libs/LibChangelog/LibChangelog.lua
create mode 100644 libs/LibChangelog/LibChangelog.toc
rename Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml => libs/LibChangelog/LibChangelog.xml (81%)
create mode 100644 libs/LibChangelog/README.md
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 63079fa..81c31ad 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -28,6 +28,26 @@
"RESURRECT_REQUEST",
"Add",
"SlashCmdList",
- "hash_SlashCmdList"
- ]
+ "hash_SlashCmdList",
+ "ButtonFrameTemplate_HidePortrait",
+ "FrameUtil",
+ "SECONDS_PER_MIN",
+ "SECONDS_PER_DAY",
+ "SECONDS_PER_HOUR",
+ "HOURS_MINUTES_SECONDS",
+ "MINUTES_SECONDS"
+ ],
+ "Lua.runtime.version": "Lua 5.1",
+ "Lua.runtime.builtin": {
+ "basic": "disable",
+ "debug": "disable",
+ "io": "disable",
+ "math": "disable",
+ "os": "disable",
+ "package": "disable",
+ "string": "disable",
+ "table": "disable",
+ "utf8": "disable"
+ },
+ "Lua.workspace.library": ["~\\.vscode\\extensions\\ketho.wow-api-0.17.6\\Annotations"]
}
diff --git a/AutoBodyRes.lua b/AutoBodyRes.lua
index 4e06b1f..78495ec 100644
--- a/AutoBodyRes.lua
+++ b/AutoBodyRes.lua
@@ -1,8 +1,7 @@
-local AddonName, NS = ...
+local _, NS = ...
local Interface = NS.Interface
-local LibStub = LibStub
local GetInstanceInfo = GetInstanceInfo
local IsInInstance = IsInInstance
local GetCorpseRecoveryDelay = GetCorpseRecoveryDelay -- Time left before a player can accept a resurrection.
@@ -11,7 +10,9 @@ local GetCorpseRecoveryDelay = GetCorpseRecoveryDelay -- Time left before a play
local After = C_Timer.After
local Ticker = C_Timer.NewTicker
-AutoBodyRes = LibStub("AceAddon-3.0"):NewAddon(AddonName, "AceEvent-3.0", "AceConsole-3.0")
+---@type AutoBodyRes
+local AutoBodyRes = NS.AutoBodyRes
+local AutoBodyResFrame = NS.AutoBodyRes.frame
local ResTicker
@@ -22,7 +23,7 @@ do
local GetSelfResurrectOptions = C_DeathInfo.GetSelfResurrectOptions -- Returns self resurrect options for your character, including from soulstones.
function AutoBodyRes:CORPSE_IN_RANGE()
- if AutoBodyRes.db.global.resurrect then
+ if NS.db.global.resurrect then
NS.RetrieveBody()
local resTime = GetCorpseRecoveryDelay()
if resTime then
@@ -36,7 +37,7 @@ do
end
function AutoBodyRes:RESURRECT_REQUEST()
- if AutoBodyRes.db.global.resurrect then
+ if NS.db.global.resurrect then
AcceptResurrect()
After(0, function()
if NS.isDead() then
@@ -54,7 +55,7 @@ do
end
function AutoBodyRes:PlayerDead()
- if AutoBodyRes.db.global.release then
+ if NS.db.global.release then
local options = GetSelfResurrectOptions()
if options and #options == 0 then
RepopMe()
@@ -66,7 +67,7 @@ do
self:PlayerDead()
local resTime = GetCorpseRecoveryDelay()
- Interface:Start(Interface, resTime + 1)
+ Interface:Start(Interface, resTime + 0.5)
end
end
@@ -90,7 +91,7 @@ function AutoBodyRes:PLAYER_SKINNED()
Interface.textFrame:Show()
Interface.flashAnimationGroup:Play()
- -- Protect Action, only available to the Blizzard UI
+ -- Protected Action, only available to the Blizzard UI
-- PortGraveyard()
After(5, function()
@@ -98,19 +99,23 @@ function AutoBodyRes:PLAYER_SKINNED()
end)
end
+local DEAD_EVENTS = {
+ "PLAYER_DEAD",
+ "PLAYER_SKINNED",
+ "CORPSE_IN_RANGE",
+ "RESURRECT_REQUEST",
+}
+
function AutoBodyRes:PlayerDeadEvents()
- self:RegisterEvent("PLAYER_DEAD")
- self:RegisterEvent("PLAYER_SKINNED")
- self:RegisterEvent("CORPSE_IN_RANGE")
- self:RegisterEvent("RESURRECT_REQUEST")
+ FrameUtil.RegisterFrameForEvents(self, DEAD_EVENTS)
self:PlayerDead()
end
function AutoBodyRes:PLAYER_ENTERING_WORLD()
- self:RegisterEvent("PLAYER_UNGHOST")
+ AutoBodyResFrame:RegisterEvent("PLAYER_UNGHOST")
- if AutoBodyRes.db.global.onlypvp then
+ if NS.db.global.onlypvp then
local inInstance = IsInInstance()
if inInstance then
@@ -120,7 +125,7 @@ function AutoBodyRes:PLAYER_ENTERING_WORLD()
if instanceType == "pvp" then
if NS.isDead() then
local resTime = GetCorpseRecoveryDelay()
- Interface:Start(Interface, resTime + 1)
+ Interface:Start(Interface, resTime + 0.5)
else
Interface:Stop(Interface, Interface.timerAnimationGroup)
Interface:Stop(Interface, Interface.flashAnimationGroup)
@@ -131,7 +136,7 @@ function AutoBodyRes:PLAYER_ENTERING_WORLD()
end)
else
After(0, function() -- Some info isn't available until 1 frame after loading is done
- if AutoBodyRes.db.global.test then
+ if NS.db.global.test then
NS.Interface.text:SetText("Placeholder")
NS.UpdateSize(NS.Interface.textFrame, NS.Interface.text)
NS.Interface.textFrame:Show()
@@ -145,28 +150,21 @@ function AutoBodyRes:PLAYER_ENTERING_WORLD()
else
if NS.isDead() then
local resTime = GetCorpseRecoveryDelay()
- Interface:Start(Interface, resTime + 1)
+ Interface:Start(Interface, resTime + 0.5)
else
Interface:Stop(Interface, Interface.timerAnimationGroup)
Interface:Stop(Interface, Interface.flashAnimationGroup)
end
- AutoBodyRes:PlayerDeadEvents()
+ self:PlayerDeadEvents()
end
end
-function AutoBodyRes:SlashCommands(_)
- LibStub("AceConfigDialog-3.0"):Open(AddonName)
-end
+function AutoBodyRes:PLAYER_LOGIN()
+ AutoBodyResFrame:UnregisterEvent("PLAYER_LOGIN")
-function AutoBodyRes:OnInitialize()
- self.db = LibStub("AceDB-3.0"):New(AddonName .. "DB", NS.DefaultDatabase, true)
- self:SetupOptions()
- self:RegisterChatCommand(AddonName, "SlashCommands")
- self:RegisterChatCommand("abr", "SlashCommands")
-end
-
-function AutoBodyRes:OnEnable()
Interface:CreateInterface()
- self:RegisterEvent("PLAYER_ENTERING_WORLD")
+
+ AutoBodyResFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
end
+AutoBodyResFrame:RegisterEvent("PLAYER_LOGIN")
diff --git a/AutoBodyRes.toc b/AutoBodyRes.toc
index 2ec25ec..975e804 100644
--- a/AutoBodyRes.toc
+++ b/AutoBodyRes.toc
@@ -1,11 +1,10 @@
-## Interface: 100207
-## Title: Auto Body Res
-## Version: 1.0.8
-## Author: Ajax
+## Interface: 110002
+## Title: AutoBodyRes
+## Version: 1.1.0
+## Author: RBGDEV
## Notes: Shows text if someone took your body or not after you died in a battleground, preventing you from being able to body res.
## OptionalDeps: Ace3, LibStub, LibSharedMedia-3.0, AceGUI-3.0-SharedMediaWidgets
## IconTexture: Interface\AddOns\AutoBodyRes\logo.tga
-## DefaultState: Enabled
## SavedVariables: AutoBodyResDB
## X-Category: Battlegrounds/PvP
## X-Credits: Ajax
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 107921d..dbf0c80 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,15 @@
# Auto Body Res
+## [v1.1.0](https://github.com/rbgdevx/auto-body-res/releases/tag/v1.1.0) (2024-09-02)
+
+- Refactor lib usage to match what im doing on BGWC addon to reduce needed libs and global db issues
+- Made it so you can't open the settings when locked and right clicking the text
+- Minor random changes based on learning from BGWC
+
## [v1.0.8](https://github.com/rbgdevx/auto-body-res/releases/tag/v1.0.8) (2024-05-08)
- Fixing 10.2.7 bugs for incorrect setting of text justification
+- Unregistering events from pvp if toggled off
## [v1.0.7](https://github.com/rbgdevx/auto-body-res/releases/tag/v1.0.7) (2024-01-09)
diff --git a/Libs/AceAddon-3.0/AceAddon-3.0.lua b/Libs/AceAddon-3.0/AceAddon-3.0.lua
deleted file mode 100644
index f392a21..0000000
--- a/Libs/AceAddon-3.0/AceAddon-3.0.lua
+++ /dev/null
@@ -1,649 +0,0 @@
---- **AceAddon-3.0** provides a template for creating addon objects.
--- It'll provide you with a set of callback functions that allow you to simplify the loading
--- process of your addon.\\
--- Callbacks provided are:\\
--- * **OnInitialize**, which is called directly after the addon is fully loaded.
--- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present.
--- * **OnDisable**, which is only called when your addon is manually being disabled.
--- @usage
--- -- A small (but complete) addon, that doesn't do anything,
--- -- but shows usage of the callbacks.
--- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
---
--- function MyAddon:OnInitialize()
--- -- do init tasks here, like loading the Saved Variables,
--- -- or setting up slash commands.
--- end
---
--- function MyAddon:OnEnable()
--- -- Do more initialization here, that really enables the use of your addon.
--- -- Register Events, Hook functions, Create Frames, Get information from
--- -- the game that wasn't available in OnInitialize
--- end
---
--- function MyAddon:OnDisable()
--- -- Unhook, Unregister Events, Hide frames that you created.
--- -- You would probably only use an OnDisable if you want to
--- -- build a "standby" mode, or be able to toggle modules on/off.
--- end
--- @class file
--- @name AceAddon-3.0.lua
--- @release $Id: AceAddon-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
-
-local MAJOR, MINOR = "AceAddon-3.0", 13
-local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not AceAddon then return end -- No Upgrade needed.
-
-AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame
-AceAddon.addons = AceAddon.addons or {} -- addons in general
-AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon.
-AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized
-AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled
-AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon
-
--- Lua APIs
-local tinsert, tconcat, tremove = table.insert, table.concat, table.remove
-local fmt, tostring = string.format, tostring
-local select, pairs, next, type, unpack = select, pairs, next, type, unpack
-local loadstring, assert, error = loadstring, assert, error
-local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
-
---[[
- xpcall safecall implementation
-]]
-local xpcall = xpcall
-
-local function errorhandler(err)
- return geterrorhandler()(err)
-end
-
-local function safecall(func, ...)
- -- we check to see if the func is passed is actually a function here and don't error when it isn't
- -- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
- -- present execution should continue without hinderance
- if type(func) == "function" then
- return xpcall(func, errorhandler, ...)
- end
-end
-
--- local functions that will be implemented further down
-local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
-
--- used in the addon metatable
-local function addontostring( self ) return self.name end
-
--- Check if the addon is queued for initialization
-local function queuedForInitialization(addon)
- for i = 1, #AceAddon.initializequeue do
- if AceAddon.initializequeue[i] == addon then
- return true
- end
- end
- return false
-end
-
---- Create a new AceAddon-3.0 addon.
--- Any libraries you specified will be embeded, and the addon will be scheduled for
--- its OnInitialize and OnEnable callbacks.
--- The final addon object, with all libraries embeded, will be returned.
--- @paramsig [object ,]name[, lib, ...]
--- @param object Table to use as a base for the addon (optional)
--- @param name Name of the addon object to create
--- @param lib List of libraries to embed into the addon
--- @usage
--- -- Create a simple addon object
--- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0")
---
--- -- Create a Addon object based on the table of a frame
--- local MyFrame = CreateFrame("Frame")
--- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0")
-function AceAddon:NewAddon(objectorname, ...)
- local object,name
- local i=1
- if type(objectorname)=="table" then
- object=objectorname
- name=...
- i=2
- else
- name=objectorname
- end
- if type(name)~="string" then
- error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2)
- end
- if self.addons[name] then
- error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2)
- end
-
- object = object or {}
- object.name = name
-
- local addonmeta = {}
- local oldmeta = getmetatable(object)
- if oldmeta then
- for k, v in pairs(oldmeta) do addonmeta[k] = v end
- end
- addonmeta.__tostring = addontostring
-
- setmetatable( object, addonmeta )
- self.addons[name] = object
- object.modules = {}
- object.orderedModules = {}
- object.defaultModuleLibraries = {}
- Embed( object ) -- embed NewModule, GetModule methods
- self:EmbedLibraries(object, select(i,...))
-
- -- add to queue of addons to be initialized upon ADDON_LOADED
- tinsert(self.initializequeue, object)
- return object
-end
-
-
---- Get the addon object by its name from the internal AceAddon registry.
--- Throws an error if the addon object cannot be found (except if silent is set).
--- @param name unique name of the addon object
--- @param silent if true, the addon is optional, silently return nil if its not found
--- @usage
--- -- Get the Addon
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-function AceAddon:GetAddon(name, silent)
- if not silent and not self.addons[name] then
- error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2)
- end
- return self.addons[name]
-end
-
--- - Embed a list of libraries into the specified addon.
--- This function will try to embed all of the listed libraries into the addon
--- and error if a single one fails.
---
--- **Note:** This function is for internal use by :NewAddon/:NewModule
--- @paramsig addon, [lib, ...]
--- @param addon addon object to embed the libs in
--- @param lib List of libraries to embed into the addon
-function AceAddon:EmbedLibraries(addon, ...)
- for i=1,select("#", ... ) do
- local libname = select(i, ...)
- self:EmbedLibrary(addon, libname, false, 4)
- end
-end
-
--- - Embed a library into the addon object.
--- This function will check if the specified library is registered with LibStub
--- and if it has a :Embed function to call. It'll error if any of those conditions
--- fails.
---
--- **Note:** This function is for internal use by :EmbedLibraries
--- @paramsig addon, libname[, silent[, offset]]
--- @param addon addon object to embed the library in
--- @param libname name of the library to embed
--- @param silent marks an embed to fail silently if the library doesn't exist (optional)
--- @param offset will push the error messages back to said offset, defaults to 2 (optional)
-function AceAddon:EmbedLibrary(addon, libname, silent, offset)
- local lib = LibStub:GetLibrary(libname, true)
- if not lib and not silent then
- error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2)
- elseif lib and type(lib.Embed) == "function" then
- lib:Embed(addon)
- tinsert(self.embeds[addon], libname)
- return true
- elseif lib then
- error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2)
- end
-end
-
---- Return the specified module from an addon object.
--- Throws an error if the addon object cannot be found (except if silent is set)
--- @name //addon//:GetModule
--- @paramsig name[, silent]
--- @param name unique name of the module
--- @param silent if true, the module is optional, silently return nil if its not found (optional)
--- @usage
--- -- Get the Addon
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- -- Get the Module
--- MyModule = MyAddon:GetModule("MyModule")
-function GetModule(self, name, silent)
- if not self.modules[name] and not silent then
- error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2)
- end
- return self.modules[name]
-end
-
-local function IsModuleTrue(self) return true end
-
---- Create a new module for the addon.
--- The new module can have its own embeded libraries and/or use a module prototype to be mixed into the module.\\
--- A module has the same functionality as a real addon, it can have modules of its own, and has the same API as
--- an addon object.
--- @name //addon//:NewModule
--- @paramsig name[, prototype|lib[, lib, ...]]
--- @param name unique name of the module
--- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional)
--- @param lib List of libraries to embed into the addon
--- @usage
--- -- Create a module with some embeded libraries
--- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0")
---
--- -- Create a module with a prototype
--- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
--- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0")
-function NewModule(self, name, prototype, ...)
- if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
- if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end
-
- if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
-
- -- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
- -- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is.
- local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name))
-
- module.IsModule = IsModuleTrue
- module:SetEnabledState(self.defaultModuleState)
- module.moduleName = name
-
- if type(prototype) == "string" then
- AceAddon:EmbedLibraries(module, prototype, ...)
- else
- AceAddon:EmbedLibraries(module, ...)
- end
- AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
-
- if not prototype or type(prototype) == "string" then
- prototype = self.defaultModulePrototype or nil
- end
-
- if type(prototype) == "table" then
- local mt = getmetatable(module)
- mt.__index = prototype
- setmetatable(module, mt) -- More of a Base class type feel.
- end
-
- safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy.
- self.modules[name] = module
- tinsert(self.orderedModules, module)
-
- return module
-end
-
---- Returns the real name of the addon or module, without any prefix.
--- @name //addon//:GetName
--- @paramsig
--- @usage
--- print(MyAddon:GetName())
--- -- prints "MyAddon"
-function GetName(self)
- return self.moduleName or self.name
-end
-
---- Enables the Addon, if possible, return true or false depending on success.
--- This internally calls AceAddon:EnableAddon(), thus dispatching a OnEnable callback
--- and enabling all modules of the addon (unless explicitly disabled).\\
--- :Enable() also sets the internal `enableState` variable to true
--- @name //addon//:Enable
--- @paramsig
--- @usage
--- -- Enable MyModule
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyModule = MyAddon:GetModule("MyModule")
--- MyModule:Enable()
-function Enable(self)
- self:SetEnabledState(true)
-
- -- nevcairiel 2013-04-27: don't enable an addon/module if its queued for init still
- -- it'll be enabled after the init process
- if not queuedForInitialization(self) then
- return AceAddon:EnableAddon(self)
- end
-end
-
---- Disables the Addon, if possible, return true or false depending on success.
--- This internally calls AceAddon:DisableAddon(), thus dispatching a OnDisable callback
--- and disabling all modules of the addon.\\
--- :Disable() also sets the internal `enableState` variable to false
--- @name //addon//:Disable
--- @paramsig
--- @usage
--- -- Disable MyAddon
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyAddon:Disable()
-function Disable(self)
- self:SetEnabledState(false)
- return AceAddon:DisableAddon(self)
-end
-
---- Enables the Module, if possible, return true or false depending on success.
--- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object.
--- @name //addon//:EnableModule
--- @paramsig name
--- @usage
--- -- Enable MyModule using :GetModule
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyModule = MyAddon:GetModule("MyModule")
--- MyModule:Enable()
---
--- -- Enable MyModule using the short-hand
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyAddon:EnableModule("MyModule")
-function EnableModule(self, name)
- local module = self:GetModule( name )
- return module:Enable()
-end
-
---- Disables the Module, if possible, return true or false depending on success.
--- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object.
--- @name //addon//:DisableModule
--- @paramsig name
--- @usage
--- -- Disable MyModule using :GetModule
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyModule = MyAddon:GetModule("MyModule")
--- MyModule:Disable()
---
--- -- Disable MyModule using the short-hand
--- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
--- MyAddon:DisableModule("MyModule")
-function DisableModule(self, name)
- local module = self:GetModule( name )
- return module:Disable()
-end
-
---- Set the default libraries to be mixed into all modules created by this object.
--- Note that you can only change the default module libraries before any module is created.
--- @name //addon//:SetDefaultModuleLibraries
--- @paramsig lib[, lib, ...]
--- @param lib List of libraries to embed into the addon
--- @usage
--- -- Create the addon object
--- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
--- -- Configure default libraries for modules (all modules need AceEvent-3.0)
--- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
--- -- Create a module
--- MyModule = MyAddon:NewModule("MyModule")
-function SetDefaultModuleLibraries(self, ...)
- if next(self.modules) then
- error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
- end
- self.defaultModuleLibraries = {...}
-end
-
---- Set the default state in which new modules are being created.
--- Note that you can only change the default state before any module is created.
--- @name //addon//:SetDefaultModuleState
--- @paramsig state
--- @param state Default state for new modules, true for enabled, false for disabled
--- @usage
--- -- Create the addon object
--- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
--- -- Set the default state to "disabled"
--- MyAddon:SetDefaultModuleState(false)
--- -- Create a module and explicilty enable it
--- MyModule = MyAddon:NewModule("MyModule")
--- MyModule:Enable()
-function SetDefaultModuleState(self, state)
- if next(self.modules) then
- error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2)
- end
- self.defaultModuleState = state
-end
-
---- Set the default prototype to use for new modules on creation.
--- Note that you can only change the default prototype before any module is created.
--- @name //addon//:SetDefaultModulePrototype
--- @paramsig prototype
--- @param prototype Default prototype for the new modules (table)
--- @usage
--- -- Define a prototype
--- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
--- -- Set the default prototype
--- MyAddon:SetDefaultModulePrototype(prototype)
--- -- Create a module and explicitly Enable it
--- MyModule = MyAddon:NewModule("MyModule")
--- MyModule:Enable()
--- -- should print "OnEnable called!" now
--- @see NewModule
-function SetDefaultModulePrototype(self, prototype)
- if next(self.modules) then
- error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
- end
- if type(prototype) ~= "table" then
- error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2)
- end
- self.defaultModulePrototype = prototype
-end
-
---- Set the state of an addon or module
--- This should only be called before any enabling actually happend, e.g. in/before OnInitialize.
--- @name //addon//:SetEnabledState
--- @paramsig state
--- @param state the state of an addon or module (enabled=true, disabled=false)
-function SetEnabledState(self, state)
- self.enabledState = state
-end
-
-
---- Return an iterator of all modules associated to the addon.
--- @name //addon//:IterateModules
--- @paramsig
--- @usage
--- -- Enable all modules
--- for name, module in MyAddon:IterateModules() do
--- module:Enable()
--- end
-local function IterateModules(self) return pairs(self.modules) end
-
--- Returns an iterator of all embeds in the addon
--- @name //addon//:IterateEmbeds
--- @paramsig
-local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end
-
---- Query the enabledState of an addon.
--- @name //addon//:IsEnabled
--- @paramsig
--- @usage
--- if MyAddon:IsEnabled() then
--- MyAddon:Disable()
--- end
-local function IsEnabled(self) return self.enabledState end
-local mixins = {
- NewModule = NewModule,
- GetModule = GetModule,
- Enable = Enable,
- Disable = Disable,
- EnableModule = EnableModule,
- DisableModule = DisableModule,
- IsEnabled = IsEnabled,
- SetDefaultModuleLibraries = SetDefaultModuleLibraries,
- SetDefaultModuleState = SetDefaultModuleState,
- SetDefaultModulePrototype = SetDefaultModulePrototype,
- SetEnabledState = SetEnabledState,
- IterateModules = IterateModules,
- IterateEmbeds = IterateEmbeds,
- GetName = GetName,
-}
-local function IsModule(self) return false end
-local pmixins = {
- defaultModuleState = true,
- enabledState = true,
- IsModule = IsModule,
-}
--- Embed( target )
--- target (object) - target object to embed aceaddon in
---
--- this is a local function specifically since it's meant to be only called internally
-function Embed(target, skipPMixins)
- for k, v in pairs(mixins) do
- target[k] = v
- end
- if not skipPMixins then
- for k, v in pairs(pmixins) do
- target[k] = target[k] or v
- end
- end
-end
-
-
--- - Initialize the addon after creation.
--- This function is only used internally during the ADDON_LOADED event
--- It will call the **OnInitialize** function on the addon object (if present),
--- and the **OnEmbedInitialize** function on all embeded libraries.
---
--- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
--- @param addon addon object to intialize
-function AceAddon:InitializeAddon(addon)
- safecall(addon.OnInitialize, addon)
-
- local embeds = self.embeds[addon]
- for i = 1, #embeds do
- local lib = LibStub:GetLibrary(embeds[i], true)
- if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
- end
-
- -- we don't call InitializeAddon on modules specifically, this is handled
- -- from the event handler and only done _once_
-end
-
--- - Enable the addon after creation.
--- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED,
--- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons.
--- It will call the **OnEnable** function on the addon object (if present),
--- and the **OnEmbedEnable** function on all embeded libraries.\\
--- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled.
---
--- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
--- Use :Enable on the addon itself instead.
--- @param addon addon object to enable
-function AceAddon:EnableAddon(addon)
- if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
- if self.statuses[addon.name] or not addon.enabledState then return false end
-
- -- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable.
- self.statuses[addon.name] = true
-
- safecall(addon.OnEnable, addon)
-
- -- make sure we're still enabled before continueing
- if self.statuses[addon.name] then
- local embeds = self.embeds[addon]
- for i = 1, #embeds do
- local lib = LibStub:GetLibrary(embeds[i], true)
- if lib then safecall(lib.OnEmbedEnable, lib, addon) end
- end
-
- -- enable possible modules.
- local modules = addon.orderedModules
- for i = 1, #modules do
- self:EnableAddon(modules[i])
- end
- end
- return self.statuses[addon.name] -- return true if we're disabled
-end
-
--- - Disable the addon
--- Note: This function is only used internally.
--- It will call the **OnDisable** function on the addon object (if present),
--- and the **OnEmbedDisable** function on all embeded libraries.\\
--- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled.
---
--- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
--- Use :Disable on the addon itself instead.
--- @param addon addon object to enable
-function AceAddon:DisableAddon(addon)
- if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
- if not self.statuses[addon.name] then return false end
-
- -- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
- self.statuses[addon.name] = false
-
- safecall( addon.OnDisable, addon )
-
- -- make sure we're still disabling...
- if not self.statuses[addon.name] then
- local embeds = self.embeds[addon]
- for i = 1, #embeds do
- local lib = LibStub:GetLibrary(embeds[i], true)
- if lib then safecall(lib.OnEmbedDisable, lib, addon) end
- end
- -- disable possible modules.
- local modules = addon.orderedModules
- for i = 1, #modules do
- self:DisableAddon(modules[i])
- end
- end
-
- return not self.statuses[addon.name] -- return true if we're disabled
-end
-
---- Get an iterator over all registered addons.
--- @usage
--- -- Print a list of all installed AceAddon's
--- for name, addon in AceAddon:IterateAddons() do
--- print("Addon: " .. name)
--- end
-function AceAddon:IterateAddons() return pairs(self.addons) end
-
---- Get an iterator over the internal status registry.
--- @usage
--- -- Print a list of all enabled addons
--- for name, status in AceAddon:IterateAddonStatus() do
--- if status then
--- print("EnabledAddon: " .. name)
--- end
--- end
-function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
-
--- Following Iterators are deprecated, and their addon specific versions should be used
--- e.g. addon:IterateEmbeds() instead of :IterateEmbedsOnAddon(addon)
-function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
-function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
-
--- Blizzard AddOns which can load very early in the loading process and mess with Ace3 addon loading
-local BlizzardEarlyLoadAddons = {
- Blizzard_DebugTools = true,
- Blizzard_TimeManager = true,
- Blizzard_BattlefieldMap = true,
- Blizzard_MapCanvas = true,
- Blizzard_SharedMapDataProviders = true,
- Blizzard_CombatLog = true,
-}
-
--- Event Handling
-local function onEvent(this, event, arg1)
- -- 2020-08-28 nevcairiel - ignore the load event of Blizzard addons which occur early in the loading process
- if (event == "ADDON_LOADED" and (arg1 == nil or not BlizzardEarlyLoadAddons[arg1])) or event == "PLAYER_LOGIN" then
- -- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration
- while(#AceAddon.initializequeue > 0) do
- local addon = tremove(AceAddon.initializequeue, 1)
- -- this might be an issue with recursion - TODO: validate
- if event == "ADDON_LOADED" then addon.baseName = arg1 end
- AceAddon:InitializeAddon(addon)
- tinsert(AceAddon.enablequeue, addon)
- end
-
- if IsLoggedIn() then
- while(#AceAddon.enablequeue > 0) do
- local addon = tremove(AceAddon.enablequeue, 1)
- AceAddon:EnableAddon(addon)
- end
- end
- end
-end
-
-AceAddon.frame:RegisterEvent("ADDON_LOADED")
-AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
-AceAddon.frame:SetScript("OnEvent", onEvent)
-
--- upgrade embeded
-for name, addon in pairs(AceAddon.addons) do
- Embed(addon, true)
-end
-
--- 2010-10-27 nevcairiel - add new "orderedModules" table
-if oldminor and oldminor < 10 then
- for name, addon in pairs(AceAddon.addons) do
- addon.orderedModules = {}
- for module_name, module in pairs(addon.modules) do
- tinsert(addon.orderedModules, module)
- end
- end
-end
diff --git a/Libs/AceAddon-3.0/AceAddon-3.0.xml b/Libs/AceAddon-3.0/AceAddon-3.0.xml
deleted file mode 100644
index dcf24c7..0000000
--- a/Libs/AceAddon-3.0/AceAddon-3.0.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
diff --git a/Libs/AceConfig-3.0/AceConfig-3.0.lua b/Libs/AceConfig-3.0/AceConfig-3.0.lua
index 5071cdc..ab91c9e 100644
--- a/Libs/AceConfig-3.0/AceConfig-3.0.lua
+++ b/Libs/AceConfig-3.0/AceConfig-3.0.lua
@@ -3,7 +3,7 @@
-- as well as associate it with a slash command.
-- @class file
-- @name AceConfig-3.0
--- @release $Id: AceConfig-3.0.lua 1202 2019-05-15 23:11:22Z nevcairiel $
+-- @release $Id: AceConfig-3.0.lua 1335 2024-05-05 19:35:16Z nevcairiel $
--[[
AceConfig-3.0
@@ -27,7 +27,7 @@ if not AceConfig then return end
local pcall, error, type, pairs = pcall, error, type, pairs
-- -------------------------------------------------------------------
--- :RegisterOptionsTable(appName, options, slashcmd, persist)
+-- :RegisterOptionsTable(appName, options, slashcmd)
--
-- - appName - (string) application name
-- - options - table or function ref, see AceConfigRegistry
diff --git a/Libs/AceConsole-3.0/AceConsole-3.0.lua b/Libs/AceConsole-3.0/AceConsole-3.0.lua
deleted file mode 100644
index 2361a3b..0000000
--- a/Libs/AceConsole-3.0/AceConsole-3.0.lua
+++ /dev/null
@@ -1,246 +0,0 @@
---- **AceConsole-3.0** provides registration facilities for slash commands.
--- You can register slash commands to your custom functions and use the `GetArgs` function to parse them
--- to your addons individual needs.
---
--- **AceConsole-3.0** can be embeded into your addon, either explicitly by calling AceConsole:Embed(MyAddon) or by
--- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
--- and can be accessed directly, without having to explicitly call AceConsole itself.\\
--- It is recommended to embed AceConsole, otherwise you'll have to specify a custom `self` on all calls you
--- make into AceConsole.
--- @class file
--- @name AceConsole-3.0
--- @release $Id: AceConsole-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
-local MAJOR,MINOR = "AceConsole-3.0", 7
-
-local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not AceConsole then return end -- No upgrade needed
-
-AceConsole.embeds = AceConsole.embeds or {} -- table containing objects AceConsole is embedded in.
-AceConsole.commands = AceConsole.commands or {} -- table containing commands registered
-AceConsole.weakcommands = AceConsole.weakcommands or {} -- table containing self, command => func references for weak commands that don't persist through enable/disable
-
--- Lua APIs
-local tconcat, tostring, select = table.concat, tostring, select
-local type, pairs, error = type, pairs, error
-local format, strfind, strsub = string.format, string.find, string.sub
-local max = math.max
-
--- WoW APIs
-local _G = _G
-
-local tmp={}
-local function Print(self,frame,...)
- local n=0
- if self ~= AceConsole then
- n=n+1
- tmp[n] = "|cff33ff99"..tostring( self ).."|r:"
- end
- for i=1, select("#", ...) do
- n=n+1
- tmp[n] = tostring(select(i, ...))
- end
- frame:AddMessage( tconcat(tmp," ",1,n) )
-end
-
---- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
--- @paramsig [chatframe ,] ...
--- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
--- @param ... List of any values to be printed
-function AceConsole:Print(...)
- local frame = ...
- if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
- return Print(self, frame, select(2,...))
- else
- return Print(self, DEFAULT_CHAT_FRAME, ...)
- end
-end
-
-
---- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
--- @paramsig [chatframe ,] "format"[, ...]
--- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
--- @param format Format string - same syntax as standard Lua format()
--- @param ... Arguments to the format string
-function AceConsole:Printf(...)
- local frame = ...
- if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
- return Print(self, frame, format(select(2,...)))
- else
- return Print(self, DEFAULT_CHAT_FRAME, format(...))
- end
-end
-
-
-
-
---- Register a simple chat command
--- @param command Chat command to be registered WITHOUT leading "/"
--- @param func Function to call when the slash command is being used (funcref or methodname)
--- @param persist if false, the command will be soft disabled/enabled when aceconsole is used as a mixin (default: true)
-function AceConsole:RegisterChatCommand( command, func, persist )
- if type(command)~="string" then error([[Usage: AceConsole:RegisterChatCommand( "command", func[, persist ]): 'command' - expected a string]], 2) end
-
- if persist==nil then persist=true end -- I'd rather have my addon's "/addon enable" around if the author screws up. Having some extra slash regged when it shouldnt be isn't as destructive. True is a better default. /Mikk
-
- local name = "ACECONSOLE_"..command:upper()
-
- if type( func ) == "string" then
- SlashCmdList[name] = function(input, editBox)
- self[func](self, input, editBox)
- end
- else
- SlashCmdList[name] = func
- end
- _G["SLASH_"..name.."1"] = "/"..command:lower()
- AceConsole.commands[command] = name
- -- non-persisting commands are registered for enabling disabling
- if not persist then
- if not AceConsole.weakcommands[self] then AceConsole.weakcommands[self] = {} end
- AceConsole.weakcommands[self][command] = func
- end
- return true
-end
-
---- Unregister a chatcommand
--- @param command Chat command to be unregistered WITHOUT leading "/"
-function AceConsole:UnregisterChatCommand( command )
- local name = AceConsole.commands[command]
- if name then
- SlashCmdList[name] = nil
- _G["SLASH_" .. name .. "1"] = nil
- hash_SlashCmdList["/" .. command:upper()] = nil
- AceConsole.commands[command] = nil
- end
-end
-
---- Get an iterator over all Chat Commands registered with AceConsole
--- @return Iterator (pairs) over all commands
-function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end
-
-
-local function nils(n, ...)
- if n>1 then
- return nil, nils(n-1, ...)
- elseif n==1 then
- return nil, ...
- else
- return ...
- end
-end
-
-
---- Retreive one or more space-separated arguments from a string.
--- Treats quoted strings and itemlinks as non-spaced.
--- @param str The raw argument string
--- @param numargs How many arguments to get (default 1)
--- @param startpos Where in the string to start scanning (default 1)
--- @return Returns arg1, arg2, ..., nextposition\\
--- Missing arguments will be returned as nils. 'nextposition' is returned as 1e9 at the end of the string.
-function AceConsole:GetArgs(str, numargs, startpos)
- numargs = numargs or 1
- startpos = max(startpos or 1, 1)
-
- local pos=startpos
-
- -- find start of new arg
- pos = strfind(str, "[^ ]", pos)
- if not pos then -- whoops, end of string
- return nils(numargs, 1e9)
- end
-
- if numargs<1 then
- return pos
- end
-
- -- quoted or space separated? find out which pattern to use
- local delim_or_pipe
- local ch = strsub(str, pos, pos)
- if ch=='"' then
- pos = pos + 1
- delim_or_pipe='([|"])'
- elseif ch=="'" then
- pos = pos + 1
- delim_or_pipe="([|'])"
- else
- delim_or_pipe="([| ])"
- end
-
- startpos = pos
-
- while true do
- -- find delimiter or hyperlink
- local _
- pos,_,ch = strfind(str, delim_or_pipe, pos)
-
- if not pos then break end
-
- if ch=="|" then
- -- some kind of escape
-
- if strsub(str,pos,pos+1)=="|H" then
- -- It's a |H....|hhyper link!|h
- pos=strfind(str, "|h", pos+2) -- first |h
- if not pos then break end
-
- pos=strfind(str, "|h", pos+2) -- second |h
- if not pos then break end
- elseif strsub(str,pos, pos+1) == "|T" then
- -- It's a |T....|t texture
- pos=strfind(str, "|t", pos+2)
- if not pos then break end
- end
-
- pos=pos+2 -- skip past this escape (last |h if it was a hyperlink)
-
- else
- -- found delimiter, done with this arg
- return strsub(str, startpos, pos-1), AceConsole:GetArgs(str, numargs-1, pos+1)
- end
-
- end
-
- -- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink)
- return strsub(str, startpos), nils(numargs-1, 1e9)
-end
-
-
---- embedding and embed handling
-
-local mixins = {
- "Print",
- "Printf",
- "RegisterChatCommand",
- "UnregisterChatCommand",
- "GetArgs",
-}
-
--- Embeds AceConsole into the target object making the functions from the mixins list available on target:..
--- @param target target object to embed AceBucket in
-function AceConsole:Embed( target )
- for k, v in pairs( mixins ) do
- target[v] = self[v]
- end
- self.embeds[target] = true
- return target
-end
-
-function AceConsole:OnEmbedEnable( target )
- if AceConsole.weakcommands[target] then
- for command, func in pairs( AceConsole.weakcommands[target] ) do
- target:RegisterChatCommand( command, func, false, true ) -- nonpersisting and silent registry
- end
- end
-end
-
-function AceConsole:OnEmbedDisable( target )
- if AceConsole.weakcommands[target] then
- for command, func in pairs( AceConsole.weakcommands[target] ) do
- target:UnregisterChatCommand( command ) -- TODO: this could potentially unregister a command from another application in case of command conflicts. Do we care?
- end
- end
-end
-
-for addon in pairs(AceConsole.embeds) do
- AceConsole:Embed(addon)
-end
diff --git a/Libs/AceConsole-3.0/AceConsole-3.0.xml b/Libs/AceConsole-3.0/AceConsole-3.0.xml
deleted file mode 100644
index 4f4699a..0000000
--- a/Libs/AceConsole-3.0/AceConsole-3.0.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
diff --git a/Libs/AceDB-3.0/AceDB-3.0.lua b/Libs/AceDB-3.0/AceDB-3.0.lua
deleted file mode 100644
index a8e306a..0000000
--- a/Libs/AceDB-3.0/AceDB-3.0.lua
+++ /dev/null
@@ -1,740 +0,0 @@
---- **AceDB-3.0** manages the SavedVariables of your addon.
--- It offers profile management, smart defaults and namespaces for modules.\\
--- Data can be saved in different data-types, depending on its intended usage.
--- The most common data-type is the `profile` type, which allows the user to choose
--- the active profile, and manage the profiles of all of his characters.\\
--- The following data types are available:
--- * **char** Character-specific data. Every character has its own database.
--- * **realm** Realm-specific data. All of the players characters on the same realm share this database.
--- * **class** Class-specific data. All of the players characters of the same class share this database.
--- * **race** Race-specific data. All of the players characters of the same race share this database.
--- * **faction** Faction-specific data. All of the players characters of the same faction share this database.
--- * **factionrealm** Faction and realm specific data. All of the players characters on the same realm and of the same faction share this database.
--- * **locale** Locale specific data, based on the locale of the players game client.
--- * **global** Global Data. All characters on the same account share this database.
--- * **profile** Profile-specific data. All characters using the same profile share this database. The user can control which profile should be used.
---
--- Creating a new Database using the `:New` function will return a new DBObject. A database will inherit all functions
--- of the DBObjectLib listed here. \\
--- If you create a new namespaced child-database (`:RegisterNamespace`), you'll get a DBObject as well, but note
--- that the child-databases cannot individually change their profile, and are linked to their parents profile - and because of that,
--- the profile related APIs are not available. Only `:RegisterDefaults` and `:ResetProfile` are available on child-databases.
---
--- For more details on how to use AceDB-3.0, see the [[AceDB-3.0 Tutorial]].
---
--- You may also be interested in [[libdualspec-1-0|LibDualSpec-1.0]] to do profile switching automatically when switching specs.
---
--- @usage
--- MyAddon = LibStub("AceAddon-3.0"):NewAddon("DBExample")
---
--- -- declare defaults to be used in the DB
--- local defaults = {
--- profile = {
--- setting = true,
--- }
--- }
---
--- function MyAddon:OnInitialize()
--- -- Assuming the .toc says ## SavedVariables: MyAddonDB
--- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
--- end
--- @class file
--- @name AceDB-3.0.lua
--- @release $Id: AceDB-3.0.lua 1306 2023-06-23 14:55:09Z nevcairiel $
-local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 28
-local AceDB = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
-
-if not AceDB then return end -- No upgrade needed
-
--- Lua APIs
-local type, pairs, next, error = type, pairs, next, error
-local setmetatable, rawset, rawget = setmetatable, rawset, rawget
-
--- WoW APIs
-local _G = _G
-
-AceDB.db_registry = AceDB.db_registry or {}
-AceDB.frame = AceDB.frame or CreateFrame("Frame")
-
-local CallbackHandler
-local CallbackDummy = { Fire = function() end }
-
-local DBObjectLib = {}
-
---[[-------------------------------------------------------------------------
- AceDB Utility Functions
----------------------------------------------------------------------------]]
-
--- Simple shallow copy for copying defaults
-local function copyTable(src, dest)
- if type(dest) ~= "table" then dest = {} end
- if type(src) == "table" then
- for k,v in pairs(src) do
- if type(v) == "table" then
- -- try to index the key first so that the metatable creates the defaults, if set, and use that table
- v = copyTable(v, dest[k])
- end
- dest[k] = v
- end
- end
- return dest
-end
-
--- Called to add defaults to a section of the database
---
--- When a ["*"] default section is indexed with a new key, a table is returned
--- and set in the host table. These tables must be cleaned up by removeDefaults
--- in order to ensure we don't write empty default tables.
-local function copyDefaults(dest, src)
- -- this happens if some value in the SV overwrites our default value with a non-table
- --if type(dest) ~= "table" then return end
- for k, v in pairs(src) do
- if k == "*" or k == "**" then
- if type(v) == "table" then
- -- This is a metatable used for table defaults
- local mt = {
- -- This handles the lookup and creation of new subtables
- __index = function(t,k2)
- if k2 == nil then return nil end
- local tbl = {}
- copyDefaults(tbl, v)
- rawset(t, k2, tbl)
- return tbl
- end,
- }
- setmetatable(dest, mt)
- -- handle already existing tables in the SV
- for dk, dv in pairs(dest) do
- if not rawget(src, dk) and type(dv) == "table" then
- copyDefaults(dv, v)
- end
- end
- else
- -- Values are not tables, so this is just a simple return
- local mt = {__index = function(t,k2) return k2~=nil and v or nil end}
- setmetatable(dest, mt)
- end
- elseif type(v) == "table" then
- if not rawget(dest, k) then rawset(dest, k, {}) end
- if type(dest[k]) == "table" then
- copyDefaults(dest[k], v)
- if src['**'] then
- copyDefaults(dest[k], src['**'])
- end
- end
- else
- if rawget(dest, k) == nil then
- rawset(dest, k, v)
- end
- end
- end
-end
-
--- Called to remove all defaults in the default table from the database
-local function removeDefaults(db, defaults, blocker)
- -- remove all metatables from the db, so we don't accidentally create new sub-tables through them
- setmetatable(db, nil)
- -- loop through the defaults and remove their content
- for k,v in pairs(defaults) do
- if k == "*" or k == "**" then
- if type(v) == "table" then
- -- Loop through all the actual k,v pairs and remove
- for key, value in pairs(db) do
- if type(value) == "table" then
- -- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
- if defaults[key] == nil and (not blocker or blocker[key] == nil) then
- removeDefaults(value, v)
- -- if the table is empty afterwards, remove it
- if next(value) == nil then
- db[key] = nil
- end
- -- if it was specified, only strip ** content, but block values which were set in the key table
- elseif k == "**" then
- removeDefaults(value, v, defaults[key])
- end
- end
- end
- elseif k == "*" then
- -- check for non-table default
- for key, value in pairs(db) do
- if defaults[key] == nil and v == value then
- db[key] = nil
- end
- end
- end
- elseif type(v) == "table" and type(db[k]) == "table" then
- -- if a blocker was set, dive into it, to allow multi-level defaults
- removeDefaults(db[k], v, blocker and blocker[k])
- if next(db[k]) == nil then
- db[k] = nil
- end
- else
- -- check if the current value matches the default, and that its not blocked by another defaults table
- if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then
- db[k] = nil
- end
- end
- end
-end
-
--- This is called when a table section is first accessed, to set up the defaults
-local function initSection(db, section, svstore, key, defaults)
- local sv = rawget(db, "sv")
-
- local tableCreated
- if not sv[svstore] then sv[svstore] = {} end
- if not sv[svstore][key] then
- sv[svstore][key] = {}
- tableCreated = true
- end
-
- local tbl = sv[svstore][key]
-
- if defaults then
- copyDefaults(tbl, defaults)
- end
- rawset(db, section, tbl)
-
- return tableCreated, tbl
-end
-
--- Metatable to handle the dynamic creation of sections and copying of sections.
-local dbmt = {
- __index = function(t, section)
- local keys = rawget(t, "keys")
- local key = keys[section]
- if key then
- local defaultTbl = rawget(t, "defaults")
- local defaults = defaultTbl and defaultTbl[section]
-
- if section == "profile" then
- local new = initSection(t, section, "profiles", key, defaults)
- if new then
- -- Callback: OnNewProfile, database, newProfileKey
- t.callbacks:Fire("OnNewProfile", t, key)
- end
- elseif section == "profiles" then
- local sv = rawget(t, "sv")
- if not sv.profiles then sv.profiles = {} end
- rawset(t, "profiles", sv.profiles)
- elseif section == "global" then
- local sv = rawget(t, "sv")
- if not sv.global then sv.global = {} end
- if defaults then
- copyDefaults(sv.global, defaults)
- end
- rawset(t, section, sv.global)
- else
- initSection(t, section, section, key, defaults)
- end
- end
-
- return rawget(t, section)
- end
-}
-
-local function validateDefaults(defaults, keyTbl, offset)
- if not defaults then return end
- offset = offset or 0
- for k in pairs(defaults) do
- if not keyTbl[k] or k == "profiles" then
- error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
- end
- end
-end
-
-local preserve_keys = {
- ["callbacks"] = true,
- ["RegisterCallback"] = true,
- ["UnregisterCallback"] = true,
- ["UnregisterAllCallbacks"] = true,
- ["children"] = true,
-}
-
-local realmKey = GetRealmName()
-local charKey = UnitName("player") .. " - " .. realmKey
-local _, classKey = UnitClass("player")
-local _, raceKey = UnitRace("player")
-local factionKey = UnitFactionGroup("player")
-local factionrealmKey = factionKey .. " - " .. realmKey
-local localeKey = GetLocale():lower()
-
-local regionTable = { "US", "KR", "EU", "TW", "CN" }
-local regionKey = regionTable[GetCurrentRegion()] or GetCurrentRegionName() or "TR"
-local factionrealmregionKey = factionrealmKey .. " - " .. regionKey
-
--- Actual database initialization function
-local function initdb(sv, defaults, defaultProfile, olddb, parent)
- -- Generate the database keys for each section
-
- -- map "true" to our "Default" profile
- if defaultProfile == true then defaultProfile = "Default" end
-
- local profileKey
- if not parent then
- -- Make a container for profile keys
- if not sv.profileKeys then sv.profileKeys = {} end
-
- -- Try to get the profile selected from the char db
- profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
-
- -- save the selected profile for later
- sv.profileKeys[charKey] = profileKey
- else
- -- Use the profile of the parents DB
- profileKey = parent.keys.profile or defaultProfile or charKey
-
- -- clear the profileKeys in the DB, namespaces don't need to store them
- sv.profileKeys = nil
- end
-
- -- This table contains keys that enable the dynamic creation
- -- of each section of the table. The 'global' and 'profiles'
- -- have a key of true, since they are handled in a special case
- local keyTbl= {
- ["char"] = charKey,
- ["realm"] = realmKey,
- ["class"] = classKey,
- ["race"] = raceKey,
- ["faction"] = factionKey,
- ["factionrealm"] = factionrealmKey,
- ["factionrealmregion"] = factionrealmregionKey,
- ["profile"] = profileKey,
- ["locale"] = localeKey,
- ["global"] = true,
- ["profiles"] = true,
- }
-
- validateDefaults(defaults, keyTbl, 1)
-
- -- This allows us to use this function to reset an entire database
- -- Clear out the old database
- if olddb then
- for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end
- end
-
- -- Give this database the metatable so it initializes dynamically
- local db = setmetatable(olddb or {}, dbmt)
-
- if not rawget(db, "callbacks") then
- -- try to load CallbackHandler-1.0 if it loaded after our library
- if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end
- db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy
- end
-
- -- Copy methods locally into the database object, to avoid hitting
- -- the metatable when calling methods
-
- if not parent then
- for name, func in pairs(DBObjectLib) do
- db[name] = func
- end
- else
- -- hack this one in
- db.RegisterDefaults = DBObjectLib.RegisterDefaults
- db.ResetProfile = DBObjectLib.ResetProfile
- end
-
- -- Set some properties in the database object
- db.profiles = sv.profiles
- db.keys = keyTbl
- db.sv = sv
- --db.sv_name = name
- db.defaults = defaults
- db.parent = parent
-
- -- store the DB in the registry
- AceDB.db_registry[db] = true
-
- return db
-end
-
--- handle PLAYER_LOGOUT
--- strip all defaults from all databases
--- and cleans up empty sections
-local function logoutHandler(frame, event)
- if event == "PLAYER_LOGOUT" then
- for db in pairs(AceDB.db_registry) do
- db.callbacks:Fire("OnDatabaseShutdown", db)
- db:RegisterDefaults(nil)
-
- -- cleanup sections that are empty without defaults
- local sv = rawget(db, "sv")
- for section in pairs(db.keys) do
- if rawget(sv, section) then
- -- global is special, all other sections have sub-entrys
- -- also don't delete empty profiles on main dbs, only on namespaces
- if section ~= "global" and (section ~= "profiles" or rawget(db, "parent")) then
- for key in pairs(sv[section]) do
- if not next(sv[section][key]) then
- sv[section][key] = nil
- end
- end
- end
- if not next(sv[section]) then
- sv[section] = nil
- end
- end
- end
- end
- end
-end
-
-AceDB.frame:RegisterEvent("PLAYER_LOGOUT")
-AceDB.frame:SetScript("OnEvent", logoutHandler)
-
-
---[[-------------------------------------------------------------------------
- AceDB Object Method Definitions
----------------------------------------------------------------------------]]
-
---- Sets the defaults table for the given database object by clearing any
--- that are currently set, and then setting the new defaults.
--- @param defaults A table of defaults for this database
-function DBObjectLib:RegisterDefaults(defaults)
- if defaults and type(defaults) ~= "table" then
- error(("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2)
- end
-
- validateDefaults(defaults, self.keys)
-
- -- Remove any currently set defaults
- if self.defaults then
- for section,key in pairs(self.keys) do
- if self.defaults[section] and rawget(self, section) then
- removeDefaults(self[section], self.defaults[section])
- end
- end
- end
-
- -- Set the DBObject.defaults table
- self.defaults = defaults
-
- -- Copy in any defaults, only touching those sections already created
- if defaults then
- for section,key in pairs(self.keys) do
- if defaults[section] and rawget(self, section) then
- copyDefaults(self[section], defaults[section])
- end
- end
- end
-end
-
---- Changes the profile of the database and all of it's namespaces to the
--- supplied named profile
--- @param name The name of the profile to set as the current profile
-function DBObjectLib:SetProfile(name)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:SetProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
- end
-
- -- changing to the same profile, dont do anything
- if name == self.keys.profile then return end
-
- local oldProfile = self.profile
- local defaults = self.defaults and self.defaults.profile
-
- -- Callback: OnProfileShutdown, database
- self.callbacks:Fire("OnProfileShutdown", self)
-
- if oldProfile and defaults then
- -- Remove the defaults from the old profile
- removeDefaults(oldProfile, defaults)
- end
-
- self.profile = nil
- self.keys["profile"] = name
-
- -- if the storage exists, save the new profile
- -- this won't exist on namespaces.
- if self.sv.profileKeys then
- self.sv.profileKeys[charKey] = name
- end
-
- -- populate to child namespaces
- if self.children then
- for _, db in pairs(self.children) do
- DBObjectLib.SetProfile(db, name)
- end
- end
-
- -- Callback: OnProfileChanged, database, newProfileKey
- self.callbacks:Fire("OnProfileChanged", self, name)
-end
-
---- Returns a table with the names of the existing profiles in the database.
--- You can optionally supply a table to re-use for this purpose.
--- @param tbl A table to store the profile names in (optional)
-function DBObjectLib:GetProfiles(tbl)
- if tbl and type(tbl) ~= "table" then
- error(("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected, got %q."):format(type(tbl)), 2)
- end
-
- -- Clear the container table
- if tbl then
- for k,v in pairs(tbl) do tbl[k] = nil end
- else
- tbl = {}
- end
-
- local curProfile = self.keys.profile
-
- local i = 0
- for profileKey in pairs(self.profiles) do
- i = i + 1
- tbl[i] = profileKey
- if curProfile and profileKey == curProfile then curProfile = nil end
- end
-
- -- Add the current profile, if it hasn't been created yet
- if curProfile then
- i = i + 1
- tbl[i] = curProfile
- end
-
- return tbl, i
-end
-
---- Returns the current profile name used by the database
-function DBObjectLib:GetCurrentProfile()
- return self.keys.profile
-end
-
---- Deletes a named profile. This profile must not be the active profile.
--- @param name The name of the profile to be deleted
--- @param silent If true, do not raise an error when the profile does not exist
-function DBObjectLib:DeleteProfile(name, silent)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
- end
-
- if self.keys.profile == name then
- error(("Cannot delete the active profile (%q) in an AceDBObject."):format(name), 2)
- end
-
- if not rawget(self.profiles, name) and not silent then
- error(("Cannot delete profile %q as it does not exist."):format(name), 2)
- end
-
- self.profiles[name] = nil
-
- -- populate to child namespaces
- if self.children then
- for _, db in pairs(self.children) do
- DBObjectLib.DeleteProfile(db, name, true)
- end
- end
-
- -- switch all characters that use this profile back to the default
- if self.sv.profileKeys then
- for key, profile in pairs(self.sv.profileKeys) do
- if profile == name then
- self.sv.profileKeys[key] = nil
- end
- end
- end
-
- -- Callback: OnProfileDeleted, database, profileKey
- self.callbacks:Fire("OnProfileDeleted", self, name)
-end
-
---- Copies a named profile into the current profile, overwriting any conflicting
--- settings.
--- @param name The name of the profile to be copied into the current profile
--- @param silent If true, do not raise an error when the profile does not exist
-function DBObjectLib:CopyProfile(name, silent)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:CopyProfile(name): 'name' - string expected, got %q."):format(type(name)), 2)
- end
-
- if name == self.keys.profile then
- error(("Cannot have the same source and destination profiles (%q)."):format(name), 2)
- end
-
- if not rawget(self.profiles, name) and not silent then
- error(("Cannot copy profile %q as it does not exist."):format(name), 2)
- end
-
- -- Reset the profile before copying
- DBObjectLib.ResetProfile(self, nil, true)
-
- local profile = self.profile
- local source = self.profiles[name]
-
- copyTable(source, profile)
-
- -- populate to child namespaces
- if self.children then
- for _, db in pairs(self.children) do
- DBObjectLib.CopyProfile(db, name, true)
- end
- end
-
- -- Callback: OnProfileCopied, database, sourceProfileKey
- self.callbacks:Fire("OnProfileCopied", self, name)
-end
-
---- Resets the current profile to the default values (if specified).
--- @param noChildren if set to true, the reset will not be populated to the child namespaces of this DB object
--- @param noCallbacks if set to true, won't fire the OnProfileReset callback
-function DBObjectLib:ResetProfile(noChildren, noCallbacks)
- local profile = self.profile
-
- for k,v in pairs(profile) do
- profile[k] = nil
- end
-
- local defaults = self.defaults and self.defaults.profile
- if defaults then
- copyDefaults(profile, defaults)
- end
-
- -- populate to child namespaces
- if self.children and not noChildren then
- for _, db in pairs(self.children) do
- DBObjectLib.ResetProfile(db, nil, noCallbacks)
- end
- end
-
- -- Callback: OnProfileReset, database
- if not noCallbacks then
- self.callbacks:Fire("OnProfileReset", self)
- end
-end
-
---- Resets the entire database, using the string defaultProfile as the new default
--- profile.
--- @param defaultProfile The profile name to use as the default
-function DBObjectLib:ResetDB(defaultProfile)
- if defaultProfile and type(defaultProfile) ~= "string" then
- error(("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected, got %q."):format(type(defaultProfile)), 2)
- end
-
- local sv = self.sv
- for k,v in pairs(sv) do
- sv[k] = nil
- end
-
- initdb(sv, self.defaults, defaultProfile, self)
-
- -- fix the child namespaces
- if self.children then
- if not sv.namespaces then sv.namespaces = {} end
- for name, db in pairs(self.children) do
- if not sv.namespaces[name] then sv.namespaces[name] = {} end
- initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self)
- end
- end
-
- -- Callback: OnDatabaseReset, database
- self.callbacks:Fire("OnDatabaseReset", self)
- -- Callback: OnProfileChanged, database, profileKey
- self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
-
- return self
-end
-
---- Creates a new database namespace, directly tied to the database. This
--- is a full scale database in it's own rights other than the fact that
--- it cannot control its profile individually
--- @param name The name of the new namespace
--- @param defaults A table of values to use as defaults
-function DBObjectLib:RegisterNamespace(name, defaults)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected, got %q."):format(type(name)), 2)
- end
- if defaults and type(defaults) ~= "table" then
- error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected, got %q."):format(type(defaults)), 2)
- end
- if self.children and self.children[name] then
- error(("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace called %q already exists."):format(name), 2)
- end
-
- local sv = self.sv
- if not sv.namespaces then sv.namespaces = {} end
- if not sv.namespaces[name] then
- sv.namespaces[name] = {}
- end
-
- local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self)
-
- if not self.children then self.children = {} end
- self.children[name] = newDB
- return newDB
-end
-
---- Returns an already existing namespace from the database object.
--- @param name The name of the new namespace
--- @param silent if true, the addon is optional, silently return nil if its not found
--- @usage
--- local namespace = self.db:GetNamespace('namespace')
--- @return the namespace object if found
-function DBObjectLib:GetNamespace(name, silent)
- if type(name) ~= "string" then
- error(("Usage: AceDBObject:GetNamespace(name): 'name' - string expected, got %q."):format(type(name)), 2)
- end
- if not silent and not (self.children and self.children[name]) then
- error(("Usage: AceDBObject:GetNamespace(name): 'name' - namespace %q does not exist."):format(name), 2)
- end
- if not self.children then self.children = {} end
- return self.children[name]
-end
-
---[[-------------------------------------------------------------------------
- AceDB Exposed Methods
----------------------------------------------------------------------------]]
-
---- Creates a new database object that can be used to handle database settings and profiles.
--- By default, an empty DB is created, using a character specific profile.
---
--- You can override the default profile used by passing any profile name as the third argument,
--- or by passing //true// as the third argument to use a globally shared profile called "Default".
---
--- Note that there is no token replacement in the default profile name, passing a defaultProfile as "char"
--- will use a profile named "char", and not a character-specific profile.
--- @param tbl The name of variable, or table to use for the database
--- @param defaults A table of database defaults
--- @param defaultProfile The name of the default profile. If not set, a character specific profile will be used as the default.
--- You can also pass //true// to use a shared global profile called "Default".
--- @usage
--- -- Create an empty DB using a character-specific default profile.
--- self.db = LibStub("AceDB-3.0"):New("MyAddonDB")
--- @usage
--- -- Create a DB using defaults and using a shared default profile
--- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
-function AceDB:New(tbl, defaults, defaultProfile)
- if type(tbl) == "string" then
- local name = tbl
- tbl = _G[name]
- if not tbl then
- tbl = {}
- _G[name] = tbl
- end
- end
-
- if type(tbl) ~= "table" then
- error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected, got %q."):format(type(tbl)), 2)
- end
-
- if defaults and type(defaults) ~= "table" then
- error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected, got %q."):format(type(defaults)), 2)
- end
-
- if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
- error(("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected, got %q."):format(type(defaultProfile)), 2)
- end
-
- return initdb(tbl, defaults, defaultProfile)
-end
-
--- upgrade existing databases
-for db in pairs(AceDB.db_registry) do
- if not db.parent then
- for name,func in pairs(DBObjectLib) do
- db[name] = func
- end
- else
- db.RegisterDefaults = DBObjectLib.RegisterDefaults
- db.ResetProfile = DBObjectLib.ResetProfile
- end
-end
diff --git a/Libs/AceDB-3.0/AceDB-3.0.xml b/Libs/AceDB-3.0/AceDB-3.0.xml
deleted file mode 100644
index 108fc70..0000000
--- a/Libs/AceDB-3.0/AceDB-3.0.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
diff --git a/Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua b/Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua
deleted file mode 100644
index 46a85bf..0000000
--- a/Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua
+++ /dev/null
@@ -1,456 +0,0 @@
---- AceDBOptions-3.0 provides a universal AceConfig options screen for managing AceDB-3.0 profiles.
--- @class file
--- @name AceDBOptions-3.0
--- @release $Id: AceDBOptions-3.0.lua 1304 2023-05-19 19:50:10Z nevcairiel $
-local ACEDBO_MAJOR, ACEDBO_MINOR = "AceDBOptions-3.0", 15
-local AceDBOptions = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR)
-
-if not AceDBOptions then return end -- No upgrade needed
-
--- Lua APIs
-local pairs, next = pairs, next
-
--- WoW APIs
-local UnitClass = UnitClass
-
-AceDBOptions.optionTables = AceDBOptions.optionTables or {}
-AceDBOptions.handlers = AceDBOptions.handlers or {}
-
---[[
- Localization of AceDBOptions-3.0
-]]
-
-local L = {
- choose = "Existing Profiles",
- choose_desc = "You can either create a new profile by entering a name in the editbox, or choose one of the already existing profiles.",
- choose_sub = "Select one of your currently available profiles.",
- copy = "Copy From",
- copy_desc = "Copy the settings from one existing profile into the currently active profile.",
- current = "Current Profile:",
- default = "Default",
- delete = "Delete a Profile",
- delete_confirm = "Are you sure you want to delete the selected profile?",
- delete_desc = "Delete existing and unused profiles from the database to save space, and cleanup the SavedVariables file.",
- delete_sub = "Deletes a profile from the database.",
- intro = "You can change the active database profile, so you can have different settings for every character.",
- new = "New",
- new_sub = "Create a new empty profile.",
- profiles = "Profiles",
- profiles_sub = "Manage Profiles",
- reset = "Reset Profile",
- reset_desc = "Reset the current profile back to its default values, in case your configuration is broken, or you simply want to start over.",
- reset_sub = "Reset the current profile to the default",
-}
-
-local LOCALE = GetLocale()
-if LOCALE == "deDE" then
- L["choose"] = "Vorhandene Profile"
- L["choose_desc"] = "Du kannst ein neues Profil erstellen, indem du einen neuen Namen in der Eingabebox 'Neu' eingibst, oder wähle eines der vorhandenen Profile aus."
- L["choose_sub"] = "Wählt ein bereits vorhandenes Profil aus."
- L["copy"] = "Kopieren von..."
- L["copy_desc"] = "Kopiere die Einstellungen von einem vorhandenen Profil in das aktive Profil."
- L["current"] = "Aktuelles Profil:"
- L["default"] = "Standard"
- L["delete"] = "Profil löschen"
- L["delete_confirm"] = "Willst du das ausgewählte Profil wirklich löschen?"
- L["delete_desc"] = "Lösche vorhandene oder unbenutzte Profile aus der Datenbank, um Platz zu sparen und die SavedVariables-Datei 'sauber' zu halten."
- L["delete_sub"] = "Löscht ein Profil aus der Datenbank."
- L["intro"] = "Hier kannst du das aktive Datenbankprofil ändern, damit du verschiedene Einstellungen für jeden Charakter erstellen kannst, wodurch eine sehr flexible Konfiguration möglich wird."
- L["new"] = "Neu"
- L["new_sub"] = "Ein neues Profil erstellen."
- L["profiles"] = "Profile"
- L["profiles_sub"] = "Profile verwalten"
- L["reset"] = "Profil zurücksetzen"
- L["reset_desc"] = "Setzt das momentane Profil auf Standardwerte zurück, für den Fall, dass mit der Konfiguration etwas schief lief oder weil du einfach neu starten willst."
- L["reset_sub"] = "Das aktuelle Profil auf Standard zurücksetzen."
-elseif LOCALE == "frFR" then
- L["choose"] = "Profils existants"
- L["choose_desc"] = "Vous pouvez créer un nouveau profil en entrant un nouveau nom dans la boîte de saisie, ou en choississant un des profils déjà existants."
- L["choose_sub"] = "Permet de choisir un des profils déjà disponibles."
- L["copy"] = "Copier à partir de"
- L["copy_desc"] = "Copie les paramètres d'un profil déjà existant dans le profil actuellement actif."
- L["current"] = "Profil actuel :"
- L["default"] = "Défaut"
- L["delete"] = "Supprimer un profil"
- L["delete_confirm"] = "Etes-vous sûr de vouloir supprimer le profil sélectionné ?"
- L["delete_desc"] = "Supprime les profils existants inutilisés de la base de données afin de gagner de la place et de nettoyer le fichier SavedVariables."
- L["delete_sub"] = "Supprime un profil de la base de données."
- L["intro"] = "Vous pouvez changer le profil actuel afin d'avoir des paramètres différents pour chaque personnage, permettant ainsi d'avoir une configuration très flexible."
- L["new"] = "Nouveau"
- L["new_sub"] = "Créée un nouveau profil vierge."
- L["profiles"] = "Profils"
- L["profiles_sub"] = "Gestion des profils"
- L["reset"] = "Réinitialiser le profil"
- L["reset_desc"] = "Réinitialise le profil actuel au cas où votre configuration est corrompue ou si vous voulez tout simplement faire table rase."
- L["reset_sub"] = "Réinitialise le profil actuel avec les paramètres par défaut."
-elseif LOCALE == "koKR" then
- L["choose"] = "기존 프로필"
- L["choose_desc"] = "편집 상자에 이름을 입력하여 새로운 프로필을 만들거나 이미 존재하는 프로필 중 하나를 선택할 수 있습니다."
- L["choose_sub"] = "현재 이용할 수 있는 프로필 중 하나를 선택합니다."
- L["copy"] = "복사해 올 프로필"
- L["copy_desc"] = "기존 프로필의 설정을 현재 활성화된 프로필로 복사합니다."
- L["current"] = "현재 프로필:"
- L["default"] = "기본값"
- L["delete"] = "프로필 삭제"
- L["delete_confirm"] = "선택한 프로필을 삭제하시겠습니까?"
- L["delete_desc"] = "데이터베이스에서 기존 프로필과 사용하지 않는 프로필을 삭제하여 공간을 절약하고 SavedVariables 파일을 정리합니다."
- L["delete_sub"] = "데이터베이스에서 프로필을 삭제합니다."
- L["intro"] = "활성 데이터베이스 프로필을 변경할 수 있으며, 모든 캐릭터마다 서로 다른 설정을 지정할 수 있습니다."
- L["new"] = "새로운 프로필"
- L["new_sub"] = "비어 있는 프로필을 새로 만듭니다."
- L["profiles"] = "프로필"
- L["profiles_sub"] = "프로필 관리"
- L["reset"] = "프로필 재설정"
- L["reset_desc"] = "구성이 손상되었거나 처음부터 다시 시작하고 싶은 경우 현재 프로필을 기본값으로 재설정하세요."
- L["reset_sub"] = "현재 프로필을 기본값으로 재설정합니다"
-elseif LOCALE == "esES" or LOCALE == "esMX" then
- L["choose"] = "Perfiles existentes"
- L["choose_desc"] = "Puedes crear un nuevo perfil introduciendo un nombre en el recuadro o puedes seleccionar un perfil de los ya existentes."
- L["choose_sub"] = "Selecciona uno de los perfiles disponibles."
- L["copy"] = "Copiar de"
- L["copy_desc"] = "Copia los ajustes de un perfil existente al perfil actual."
- L["current"] = "Perfil actual:"
- L["default"] = "Por defecto"
- L["delete"] = "Borrar un Perfil"
- L["delete_confirm"] = "¿Estas seguro que quieres borrar el perfil seleccionado?"
- L["delete_desc"] = "Borra los perfiles existentes y sin uso de la base de datos para ganar espacio y limpiar el archivo SavedVariables."
- L["delete_sub"] = "Borra un perfil de la base de datos."
- L["intro"] = "Puedes cambiar el perfil activo de tal manera que cada personaje tenga diferentes configuraciones."
- L["new"] = "Nuevo"
- L["new_sub"] = "Crear un nuevo perfil vacio."
- L["profiles"] = "Perfiles"
- L["profiles_sub"] = "Manejar Perfiles"
- L["reset"] = "Reiniciar Perfil"
- L["reset_desc"] = "Reinicia el perfil actual a los valores por defectos, en caso de que se haya estropeado la configuración o quieras volver a empezar de nuevo."
- L["reset_sub"] = "Reinicar el perfil actual al de por defecto"
-elseif LOCALE == "zhTW" then
- L["choose"] = "現有的設定檔"
- L["choose_desc"] = "您可以在文字方塊內輸入名字以建立新的設定檔,或是選擇一個現有的設定檔使用。"
- L["choose_sub"] = "從當前可用的設定檔裡面選擇一個。"
- L["copy"] = "複製自"
- L["copy_desc"] = "從一個現有的設定檔,將設定複製到現在使用中的設定檔。"
- L["current"] = "目前設定檔:"
- L["default"] = "預設"
- L["delete"] = "刪除一個設定檔"
- L["delete_confirm"] = "確定要刪除所選擇的設定檔嗎?"
- L["delete_desc"] = "從資料庫裡刪除不再使用的設定檔,以節省空間,並且清理 SavedVariables 檔案。"
- L["delete_sub"] = "從資料庫裡刪除一個設定檔。"
- L["intro"] = "您可以從資料庫中選擇一個設定檔來使用,如此就可以讓每個角色使用不同的設定。"
- L["new"] = "新建"
- L["new_sub"] = "新建一個空的設定檔。"
- L["profiles"] = "設定檔"
- L["profiles_sub"] = "管理設定檔"
- L["reset"] = "重置設定檔"
- L["reset_desc"] = "將現用的設定檔重置為預設值;用於設定檔損壞,或者單純想要重來的情況。"
- L["reset_sub"] = "將目前的設定檔重置為預設值"
-elseif LOCALE == "zhCN" then
- L["choose"] = "现有的配置文件"
- L["choose_desc"] = "你可以通过在文本框内输入一个名字创立一个新的配置文件,也可以选择一个已经存在的配置文件。"
- L["choose_sub"] = "从当前可用的配置文件里面选择一个。"
- L["copy"] = "复制自"
- L["copy_desc"] = "从当前某个已保存的配置文件复制到当前正使用的配置文件。"
- L["current"] = "当前配置文件:"
- L["default"] = "默认"
- L["delete"] = "删除一个配置文件"
- L["delete_confirm"] = "你确定要删除所选择的配置文件么?"
- L["delete_desc"] = "从数据库里删除不再使用的配置文件,以节省空间,并且清理SavedVariables文件。"
- L["delete_sub"] = "从数据库里删除一个配置文件。"
- L["intro"] = "你可以选择一个活动的数据配置文件,这样你的每个角色就可以拥有不同的设置值,可以给你的插件配置带来极大的灵活性。"
- L["new"] = "新建"
- L["new_sub"] = "新建一个空的配置文件。"
- L["profiles"] = "配置文件"
- L["profiles_sub"] = "管理配置文件"
- L["reset"] = "重置配置文件"
- L["reset_desc"] = "将当前的配置文件恢复到它的默认值,用于你的配置文件损坏,或者你只是想重来的情况。"
- L["reset_sub"] = "将当前的配置文件恢复为默认值"
-elseif LOCALE == "ruRU" then
- L["choose"] = "Существующие профили"
- L["choose_desc"] = "Вы можете создать новый профиль, введя название в поле ввода, или выбрать один из уже существующих профилей."
- L["choose_sub"] = "Выбор одного из уже доступных профилей."
- L["copy"] = "Скопировать из"
- L["copy_desc"] = "Копирование настроек из выбранного профиля в активный."
- L["current"] = "Текущий профиль:"
- L["default"] = "По умолчанию"
- L["delete"] = "Удалить профиль"
- L["delete_confirm"] = "Вы уверены, что хотите удалить выбранный профиль?"
- L["delete_desc"] = "Удаление существующего и неиспользуемого профиля из базы данных для сохранения места, и очистка файла SavedVariables."
- L["delete_sub"] = "Удаление профиля из базы данных."
- L["intro"] = "Изменяя активный профиль, Вы можете задать разные настройки для каждого персонажа."
- L["new"] = "Новый"
- L["new_sub"] = "Создание нового чистого профиля."
- L["profiles"] = "Профили"
- L["profiles_sub"] = "Управление профилями"
- L["reset"] = "Сбросить профиль"
- L["reset_desc"] = "Сброс текущего профиля к стандартным настройкам, если Ваша конфигурация испорчена или Вы хотите настроить все заново."
- L["reset_sub"] = "Сброс текущего профиля на стандартный"
-elseif LOCALE == "itIT" then
- L["choose"] = "Profili Esistenti"
- L["choose_desc"] = "Puoi creare un nuovo profilo digitando il nome della casella di testo, oppure scegliendone uno tra i profili già esistenti."
- L["choose_sub"] = "Seleziona uno dei profili attualmente disponibili."
- L["copy"] = "Copia Da"
- L["copy_desc"] = "Copia le impostazioni da un profilo esistente nel profilo attivo in questo momento."
- L["current"] = "Profilo Attivo:"
- L["default"] = "Predefinito"
- L["delete"] = "Cancella un Profilo"
- L["delete_confirm"] = "Sei sicuro di voler cancellare il profilo selezionato?"
- L["delete_desc"] = "Cancella i profili non utilizzati dal database per risparmiare spazio e mantenere puliti i file di configurazione SavedVariables."
- L["delete_sub"] = "Cancella un profilo dal Database."
- L["intro"] = "Puoi cambiare il profilo attivo, in modo da usare impostazioni diverse per ogni personaggio."
- L["new"] = "Nuovo"
- L["new_sub"] = "Crea un nuovo profilo vuoto."
- L["profiles"] = "Profili"
- L["profiles_sub"] = "Gestisci Profili"
- L["reset"] = "Reimposta Profilo"
- L["reset_desc"] = "Riporta il tuo profilo attivo alle sue impostazioni predefinite, nel caso in cui la tua configurazione si sia corrotta, o semplicemente tu voglia re-inizializzarla."
- L["reset_sub"] = "Reimposta il profilo ai suoi valori predefiniti."
-elseif LOCALE == "ptBR" then
- L["choose"] = "Perfis Existentes"
- L["choose_desc"] = "Você pode tanto criar um perfil novo tanto digitando um nome na caixa de texto, quanto escolher um dos perfis já existentes."
- L["choose_sub"] = "Selecione um de seus perfis atualmente disponíveis."
- L["copy"] = "Copiar De"
- L["copy_desc"] = "Copia as definições de um perfil existente no perfil atualmente ativo."
- L["current"] = "Perfil Autal:"
- L["default"] = "Padrão"
- L["delete"] = "Remover um Perfil"
- L["delete_confirm"] = "Tem certeza que deseja remover o perfil selecionado?"
- L["delete_desc"] = "Remove perfis existentes e inutilizados do banco de dados para economizar espaço, e limpar o arquivo SavedVariables."
- L["delete_sub"] = "Remove um perfil do banco de dados."
- L["intro"] = "Você pode alterar o perfil do banco de dados ativo, para que possa ter definições diferentes para cada personagem."
- L["new"] = "Novo"
- L["new_sub"] = "Cria um novo perfil vazio."
- L["profiles"] = "Perfis"
- L["profiles_sub"] = "Gerenciar Perfis"
- L["reset"] = "Resetar Perfil"
- L["reset_desc"] = "Reseta o perfil atual para os valores padrões, no caso de sua configuração estar quebrada, ou simplesmente se deseja começar novamente."
- L["reset_sub"] = "Resetar o perfil atual ao padrão"
-end
-
-local defaultProfiles
-local tmpprofiles = {}
-
--- Get a list of available profiles for the specified database.
--- You can specify which profiles to include/exclude in the list using the two boolean parameters listed below.
--- @param db The db object to retrieve the profiles from
--- @param common If true, getProfileList will add the default profiles to the return list, even if they have not been created yet
--- @param nocurrent If true, then getProfileList will not display the current profile in the list
--- @return Hashtable of all profiles with the internal name as keys and the display name as value.
-local function getProfileList(db, common, nocurrent)
- local profiles = {}
-
- -- copy existing profiles into the table
- local currentProfile = db:GetCurrentProfile()
- for i,v in pairs(db:GetProfiles(tmpprofiles)) do
- if not (nocurrent and v == currentProfile) then
- profiles[v] = v
- end
- end
-
- -- add our default profiles to choose from ( or rename existing profiles)
- for k,v in pairs(defaultProfiles) do
- if (common or profiles[k]) and not (nocurrent and k == currentProfile) then
- profiles[k] = v
- end
- end
-
- return profiles
-end
-
---[[
- OptionsHandlerPrototype
- prototype class for handling the options in a sane way
-]]
-local OptionsHandlerPrototype = {}
-
---[[ Reset the profile ]]
-function OptionsHandlerPrototype:Reset()
- self.db:ResetProfile()
-end
-
---[[ Set the profile to value ]]
-function OptionsHandlerPrototype:SetProfile(info, value)
- self.db:SetProfile(value)
-end
-
---[[ returns the currently active profile ]]
-function OptionsHandlerPrototype:GetCurrentProfile()
- return self.db:GetCurrentProfile()
-end
-
---[[
- List all active profiles
- you can control the output with the .arg variable
- currently four modes are supported
-
- (empty) - return all available profiles
- "nocurrent" - returns all available profiles except the currently active profile
- "common" - returns all avaialble profiles + some commonly used profiles ("char - realm", "realm", "class", "Default")
- "both" - common except the active profile
-]]
-function OptionsHandlerPrototype:ListProfiles(info)
- local arg = info.arg
- local profiles
- if arg == "common" and not self.noDefaultProfiles then
- profiles = getProfileList(self.db, true, nil)
- elseif arg == "nocurrent" then
- profiles = getProfileList(self.db, nil, true)
- elseif arg == "both" then -- currently not used
- profiles = getProfileList(self.db, (not self.noDefaultProfiles) and true, true)
- else
- profiles = getProfileList(self.db)
- end
-
- return profiles
-end
-
-function OptionsHandlerPrototype:HasNoProfiles(info)
- local profiles = self:ListProfiles(info)
- return ((not next(profiles)) and true or false)
-end
-
---[[ Copy a profile ]]
-function OptionsHandlerPrototype:CopyProfile(info, value)
- self.db:CopyProfile(value)
-end
-
---[[ Delete a profile from the db ]]
-function OptionsHandlerPrototype:DeleteProfile(info, value)
- self.db:DeleteProfile(value)
-end
-
---[[ fill defaultProfiles with some generic values ]]
-local function generateDefaultProfiles(db)
- defaultProfiles = {
- ["Default"] = L["default"],
- [db.keys.char] = db.keys.char,
- [db.keys.realm] = db.keys.realm,
- [db.keys.class] = UnitClass("player")
- }
-end
-
---[[ create and return a handler object for the db, or upgrade it if it already existed ]]
-local function getOptionsHandler(db, noDefaultProfiles)
- if not defaultProfiles then
- generateDefaultProfiles(db)
- end
-
- local handler = AceDBOptions.handlers[db] or { db = db, noDefaultProfiles = noDefaultProfiles }
-
- for k,v in pairs(OptionsHandlerPrototype) do
- handler[k] = v
- end
-
- AceDBOptions.handlers[db] = handler
- return handler
-end
-
---[[
- the real options table
-]]
-local optionsTable = {
- desc = {
- order = 1,
- type = "description",
- name = L["intro"] .. "\n",
- },
- descreset = {
- order = 9,
- type = "description",
- name = L["reset_desc"],
- },
- reset = {
- order = 10,
- type = "execute",
- name = L["reset"],
- desc = L["reset_sub"],
- func = "Reset",
- },
- current = {
- order = 11,
- type = "description",
- name = function(info) return L["current"] .. " " .. NORMAL_FONT_COLOR_CODE .. info.handler:GetCurrentProfile() .. FONT_COLOR_CODE_CLOSE end,
- width = "default",
- },
- choosedesc = {
- order = 20,
- type = "description",
- name = "\n" .. L["choose_desc"],
- },
- new = {
- name = L["new"],
- desc = L["new_sub"],
- type = "input",
- order = 30,
- get = false,
- set = "SetProfile",
- },
- choose = {
- name = L["choose"],
- desc = L["choose_sub"],
- type = "select",
- order = 40,
- get = "GetCurrentProfile",
- set = "SetProfile",
- values = "ListProfiles",
- arg = "common",
- },
- copydesc = {
- order = 50,
- type = "description",
- name = "\n" .. L["copy_desc"],
- },
- copyfrom = {
- order = 60,
- type = "select",
- name = L["copy"],
- desc = L["copy_desc"],
- get = false,
- set = "CopyProfile",
- values = "ListProfiles",
- disabled = "HasNoProfiles",
- arg = "nocurrent",
- },
- deldesc = {
- order = 70,
- type = "description",
- name = "\n" .. L["delete_desc"],
- },
- delete = {
- order = 80,
- type = "select",
- name = L["delete"],
- desc = L["delete_sub"],
- get = false,
- set = "DeleteProfile",
- values = "ListProfiles",
- disabled = "HasNoProfiles",
- arg = "nocurrent",
- confirm = true,
- confirmText = L["delete_confirm"],
- },
-}
-
---- Get/Create a option table that you can use in your addon to control the profiles of AceDB-3.0.
--- @param db The database object to create the options table for.
--- @return The options table to be used in AceConfig-3.0
--- @usage
--- -- Assuming `options` is your top-level options table and `self.db` is your database:
--- options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
-function AceDBOptions:GetOptionsTable(db, noDefaultProfiles)
- local tbl = AceDBOptions.optionTables[db] or {
- type = "group",
- name = L["profiles"],
- desc = L["profiles_sub"],
- }
-
- tbl.handler = getOptionsHandler(db, noDefaultProfiles)
- tbl.args = optionsTable
-
- AceDBOptions.optionTables[db] = tbl
- return tbl
-end
-
--- upgrade existing tables
-for db,tbl in pairs(AceDBOptions.optionTables) do
- tbl.handler = getOptionsHandler(db)
- tbl.args = optionsTable
-end
diff --git a/Libs/AceEvent-3.0/AceEvent-3.0.lua b/Libs/AceEvent-3.0/AceEvent-3.0.lua
deleted file mode 100644
index 7ccd880..0000000
--- a/Libs/AceEvent-3.0/AceEvent-3.0.lua
+++ /dev/null
@@ -1,126 +0,0 @@
---- AceEvent-3.0 provides event registration and secure dispatching.
--- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around
--- CallbackHandler, and dispatches all game events or addon message to the registrees.
---
--- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by
--- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
--- and can be accessed directly, without having to explicitly call AceEvent itself.\\
--- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you
--- make into AceEvent.
--- @class file
--- @name AceEvent-3.0
--- @release $Id: AceEvent-3.0.lua 1202 2019-05-15 23:11:22Z nevcairiel $
-local CallbackHandler = LibStub("CallbackHandler-1.0")
-
-local MAJOR, MINOR = "AceEvent-3.0", 4
-local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
-
-if not AceEvent then return end
-
--- Lua APIs
-local pairs = pairs
-
-AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
-AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
-
--- APIs and registry for blizzard events, using CallbackHandler lib
-if not AceEvent.events then
- AceEvent.events = CallbackHandler:New(AceEvent,
- "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
-end
-
-function AceEvent.events:OnUsed(target, eventname)
- AceEvent.frame:RegisterEvent(eventname)
-end
-
-function AceEvent.events:OnUnused(target, eventname)
- AceEvent.frame:UnregisterEvent(eventname)
-end
-
-
--- APIs and registry for IPC messages, using CallbackHandler lib
-if not AceEvent.messages then
- AceEvent.messages = CallbackHandler:New(AceEvent,
- "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
- )
- AceEvent.SendMessage = AceEvent.messages.Fire
-end
-
---- embedding and embed handling
-local mixins = {
- "RegisterEvent", "UnregisterEvent",
- "RegisterMessage", "UnregisterMessage",
- "SendMessage",
- "UnregisterAllEvents", "UnregisterAllMessages",
-}
-
---- Register for a Blizzard Event.
--- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
--- Any arguments to the event will be passed on after that.
--- @name AceEvent:RegisterEvent
--- @class function
--- @paramsig event[, callback [, arg]]
--- @param event The event to register for
--- @param callback The callback function to call when the event is triggered (funcref or method, defaults to a method with the event name)
--- @param arg An optional argument to pass to the callback function
-
---- Unregister an event.
--- @name AceEvent:UnregisterEvent
--- @class function
--- @paramsig event
--- @param event The event to unregister
-
---- Register for a custom AceEvent-internal message.
--- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
--- Any arguments to the event will be passed on after that.
--- @name AceEvent:RegisterMessage
--- @class function
--- @paramsig message[, callback [, arg]]
--- @param message The message to register for
--- @param callback The callback function to call when the message is triggered (funcref or method, defaults to a method with the event name)
--- @param arg An optional argument to pass to the callback function
-
---- Unregister a message
--- @name AceEvent:UnregisterMessage
--- @class function
--- @paramsig message
--- @param message The message to unregister
-
---- Send a message over the AceEvent-3.0 internal message system to other addons registered for this message.
--- @name AceEvent:SendMessage
--- @class function
--- @paramsig message, ...
--- @param message The message to send
--- @param ... Any arguments to the message
-
-
--- Embeds AceEvent into the target object making the functions from the mixins list available on target:..
--- @param target target object to embed AceEvent in
-function AceEvent:Embed(target)
- for k, v in pairs(mixins) do
- target[v] = self[v]
- end
- self.embeds[target] = true
- return target
-end
-
--- AceEvent:OnEmbedDisable( target )
--- target (object) - target object that is being disabled
---
--- Unregister all events messages etc when the target disables.
--- this method should be called by the target manually or by an addon framework
-function AceEvent:OnEmbedDisable(target)
- target:UnregisterAllEvents()
- target:UnregisterAllMessages()
-end
-
--- Script to fire blizzard events into the event listeners
-local events = AceEvent.events
-AceEvent.frame:SetScript("OnEvent", function(this, event, ...)
- events:Fire(event, ...)
-end)
-
---- Finally: upgrade our old embeds
-for target, v in pairs(AceEvent.embeds) do
- AceEvent:Embed(target)
-end
diff --git a/Libs/AceEvent-3.0/AceEvent-3.0.xml b/Libs/AceEvent-3.0/AceEvent-3.0.xml
deleted file mode 100644
index 41ef791..0000000
--- a/Libs/AceEvent-3.0/AceEvent-3.0.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua
index d57b008..ec811d0 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-ColorPicker.lua
@@ -1,7 +1,7 @@
--[[-----------------------------------------------------------------------------
ColorPicker Widget
-------------------------------------------------------------------------------]]
-local Type, Version = "ColorPicker", 25
+local Type, Version = "ColorPicker", 28
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -11,13 +11,24 @@ local pairs = pairs
-- WoW APIs
local CreateFrame, UIParent = CreateFrame, UIParent
+-- Unfortunately we have no way to realistically detect if a client uses inverted alpha
+-- as no API will tell you. Wrath uses the old colorpicker, era uses the new one, both are inverted
+local INVERTED_ALPHA = (WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE)
+
--[[-----------------------------------------------------------------------------
Support functions
-------------------------------------------------------------------------------]]
local function ColorCallback(self, r, g, b, a, isAlpha)
+ if INVERTED_ALPHA and a then
+ a = 1 - a
+ end
if not self.HasAlpha then
a = 1
end
+ -- no change, skip update
+ if r == self.r and g == self.g and b == self.b and a == self.a then
+ return
+ end
self:SetColor(r, g, b, a)
if ColorPickerFrame:IsVisible() then
--colorpicker is still open
@@ -50,30 +61,63 @@ local function ColorSwatch_OnClick(frame)
ColorPickerFrame:SetFrameLevel(frame:GetFrameLevel() + 10)
ColorPickerFrame:SetClampedToScreen(true)
- ColorPickerFrame.func = function()
- local r, g, b = ColorPickerFrame:GetColorRGB()
- local a = 1 - OpacitySliderFrame:GetValue()
- ColorCallback(self, r, g, b, a)
- end
-
- ColorPickerFrame.hasOpacity = self.HasAlpha
- ColorPickerFrame.opacityFunc = function()
- local r, g, b = ColorPickerFrame:GetColorRGB()
- local a = 1 - OpacitySliderFrame:GetValue()
- ColorCallback(self, r, g, b, a, true)
- end
-
- local r, g, b, a = self.r, self.g, self.b, self.a
- if self.HasAlpha then
- ColorPickerFrame.opacity = 1 - (a or 0)
- end
- ColorPickerFrame:SetColorRGB(r, g, b)
-
- ColorPickerFrame.cancelFunc = function()
- ColorCallback(self, r, g, b, a, true)
+ if ColorPickerFrame.SetupColorPickerAndShow then -- 10.2.5 color picker overhaul
+ local r2, g2, b2, a2 = self.r, self.g, self.b, (self.a or 1)
+ if INVERTED_ALPHA then
+ a2 = 1 - a2
+ end
+
+ local info = {
+ swatchFunc = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = ColorPickerFrame:GetColorAlpha()
+ ColorCallback(self, r, g, b, a)
+ end,
+
+ hasOpacity = self.HasAlpha,
+ opacityFunc = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = ColorPickerFrame:GetColorAlpha()
+ ColorCallback(self, r, g, b, a, true)
+ end,
+ opacity = a2,
+
+ cancelFunc = function()
+ ColorCallback(self, r2, g2, b2, a2, true)
+ end,
+
+ r = r2,
+ g = g2,
+ b = b2,
+ }
+
+ ColorPickerFrame:SetupColorPickerAndShow(info)
+ else
+ ColorPickerFrame.func = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = OpacitySliderFrame:GetValue()
+ ColorCallback(self, r, g, b, a)
+ end
+
+ ColorPickerFrame.hasOpacity = self.HasAlpha
+ ColorPickerFrame.opacityFunc = function()
+ local r, g, b = ColorPickerFrame:GetColorRGB()
+ local a = OpacitySliderFrame:GetValue()
+ ColorCallback(self, r, g, b, a, true)
+ end
+
+ local r, g, b, a = self.r, self.g, self.b, 1 - (self.a or 1)
+ if self.HasAlpha then
+ ColorPickerFrame.opacity = a
+ end
+ ColorPickerFrame:SetColorRGB(r, g, b)
+
+ ColorPickerFrame.cancelFunc = function()
+ ColorCallback(self, r, g, b, a, true)
+ end
+
+ ColorPickerFrame:Show()
end
-
- ColorPickerFrame:Show()
end
AceGUI:ClearFocus()
end
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua
index bb1e4fd..f2a238b 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-EditBox.lua
@@ -1,7 +1,7 @@
--[[-----------------------------------------------------------------------------
EditBox Widget
-------------------------------------------------------------------------------]]
-local Type, Version = "EditBox", 28
+local Type, Version = "EditBox", 29
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -10,7 +10,7 @@ local tostring, pairs = tostring, pairs
-- WoW APIs
local PlaySound = PlaySound
-local GetCursorInfo, ClearCursor, GetSpellInfo = GetCursorInfo, ClearCursor, GetSpellInfo
+local GetCursorInfo, ClearCursor = GetCursorInfo, ClearCursor
local CreateFrame, UIParent = CreateFrame, UIParent
local _G = _G
@@ -76,12 +76,16 @@ end
local function EditBox_OnReceiveDrag(frame)
local self = frame.obj
- local type, id, info = GetCursorInfo()
+ local type, id, info, extra = GetCursorInfo()
local name
if type == "item" then
name = info
elseif type == "spell" then
- name = GetSpellInfo(id, info)
+ if C_Spell and C_Spell.GetSpellName then
+ name = C_Spell.GetSpellName(extra)
+ else
+ name = GetSpellInfo(id, info)
+ end
elseif type == "macro" then
name = GetMacroInfo(id)
end
diff --git a/Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua b/Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua
index bacb2be..f0095b5 100644
--- a/Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua
+++ b/Libs/AceGUI-3.0/widgets/AceGUIWidget-MultiLineEditBox.lua
@@ -1,4 +1,4 @@
-local Type, Version = "MultiLineEditBox", 32
+local Type, Version = "MultiLineEditBox", 33
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
@@ -6,7 +6,7 @@ if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
local pairs = pairs
-- WoW APIs
-local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor
+local GetCursorInfo, ClearCursor = GetCursorInfo, ClearCursor
local CreateFrame, UIParent = CreateFrame, UIParent
local _G = _G
@@ -100,9 +100,13 @@ local function OnMouseUp(self)
end
local function OnReceiveDrag(self) -- EditBox / ScrollFrame
- local type, id, info = GetCursorInfo()
+ local type, id, info, extra = GetCursorInfo()
if type == "spell" then
- info = GetSpellInfo(id, info)
+ if C_Spell and C_Spell.GetSpellName then
+ info = C_Spell.GetSpellName(extra)
+ else
+ info = GetSpellInfo(id, info)
+ end
elseif type ~= "item" then
return
end
diff --git a/Libs/LibSharedMedia-3.0/LibSharedMedia-3.0.lua b/Libs/LibSharedMedia-3.0/LibSharedMedia-3.0.lua
index fb3446c..94ee292 100644
--- a/Libs/LibSharedMedia-3.0/LibSharedMedia-3.0.lua
+++ b/Libs/LibSharedMedia-3.0/LibSharedMedia-3.0.lua
@@ -1,7 +1,7 @@
--@curseforge-project-slug: libsharedmedia-3-0@
--[[
Name: LibSharedMedia-3.0
-Revision: $Revision: 128 $
+Revision: $Revision: 151 $
Author: Elkano (elkano@gmx.de)
Inspired By: SurfaceLib by Haste/Otravi (troeks@gmail.com)
Website: http://www.wowace.com/projects/libsharedmedia-3-0/
@@ -23,11 +23,9 @@ local type = _G.type
local band = _G.bit.band
local table_sort = _G.table.sort
-local RESTRICTED_FILE_ACCESS = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE -- starting with 8.2, some rules for file access have changed; classic still uses the old way
-
local locale = GetLocale()
local locale_is_western
-local LOCALE_MASK = 0
+local LOCALE_MASK
lib.LOCALE_BIT_koKR = 1
lib.LOCALE_BIT_ruRU = 2
lib.LOCALE_BIT_zhCN = 4
@@ -199,7 +197,7 @@ lib.DefaultMedia.statusbar = "Blizzard"
-- SOUND
if not lib.MediaTable.sound then lib.MediaTable.sound = {} end
-lib.MediaTable.sound["None"] = RESTRICTED_FILE_ACCESS and 1 or [[Interface\Quiet.ogg]] -- Relies on the fact that PlaySound[File] doesn't error on these values.
+lib.MediaTable.sound["None"] = 1 -- Relies on the fact that PlaySoundFile doesn't error on this value
lib.DefaultMedia.sound = "None"
local function rebuildMediaList(mediatype)
@@ -230,7 +228,7 @@ function lib:Register(mediatype, key, data, langmask)
end
if type(data) == "string" and (mediatype == lib.MediaType.BACKGROUND or mediatype == lib.MediaType.BORDER or mediatype == lib.MediaType.STATUSBAR or mediatype == lib.MediaType.SOUND) then
local path = data:lower()
- if RESTRICTED_FILE_ACCESS and not path:find("^interface") then
+ if not path:find("^interface") then
-- files accessed via path only allowed from interface folder
return false
end
diff --git a/README.md b/README.md
index b165dd6..dd7d833 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,3 @@
# Auto Body Res
+
+Original WeakAura Version: https://wago.io/5hqOmmAPr
diff --git a/config.lua b/config.lua
index 805fc57..bd9fed9 100644
--- a/config.lua
+++ b/config.lua
@@ -1,25 +1,83 @@
local _, NS = ...
+local CreateFrame = CreateFrame
+
+---@class PositionArray
+---@field[1] string
+---@field[2] string
+---@field[3] number
+---@field[4] number
+
+---@class ColorArray
+---@field r number
+---@field g number
+---@field b number
+---@field a number
+
+---@class GlobalTable : table
+---@field lock boolean
+---@field test boolean
+---@field release boolean
+---@field onlypvp boolean
+---@field fontsize number
+---@field font string
+---@field color ColorArray
+---@field position PositionArray
+---@field debug boolean
+
+---@class DBTable : table
+---@field global GlobalTable
+
+---@class AutoBodyRes
+---@field ADDON_LOADED function
+---@field PLAYER_LOGIN function
+---@field CORPSE_IN_RANGE function
+---@field RESURRECT_REQUEST function
+---@field PLAYER_DEAD function
+---@field PLAYER_UNGHOST function
+---@field PLAYER_SKINNED function
+---@field PLAYER_ENTERING_WORLD function
+---@field PlayerDead function
+---@field PlayerDeadEvents function
+---@field SlashCommands function
+---@field frame Frame
+---@field db DBTable
+---@field isInitialized boolean
+
+---@type AutoBodyRes
+---@diagnostic disable-next-line: missing-fields
+local AutoBodyRes = {}
+NS.AutoBodyRes = AutoBodyRes
+
+local AutoBodyResFrame = CreateFrame("Frame", "AutoBodyResFrame")
+AutoBodyResFrame:SetScript("OnEvent", function(_, event, ...)
+ if AutoBodyRes[event] then
+ AutoBodyRes[event](AutoBodyRes, ...)
+ end
+end)
+NS.AutoBodyRes.frame = AutoBodyResFrame
+
NS.DefaultDatabase = {
- ["global"] = {
- ["lock"] = false,
- ["test"] = true,
- ["release"] = true,
- ["resurrect"] = true,
- ["onlypvp"] = true,
- ["fontsize"] = 40,
- ["font"] = "Friz Quadrata TT",
- ["color"] = {
- ["r"] = 176 / 255,
- ["g"] = 43 / 255,
- ["b"] = 43 / 255,
- ["a"] = 1,
+ global = {
+ lock = false,
+ test = true,
+ release = true,
+ resurrect = true,
+ onlypvp = true,
+ fontsize = 40,
+ font = "Friz Quadrata TT",
+ color = {
+ r = 176 / 255,
+ g = 43 / 255,
+ b = 43 / 255,
+ a = 1,
},
- ["position"] = {
+ position = {
"CENTER",
"CENTER",
0,
0,
},
+ debug = false,
},
}
diff --git a/embeds.xml b/embeds.xml
index 42498a8..e09cbdb 100644
--- a/embeds.xml
+++ b/embeds.xml
@@ -1,13 +1,8 @@
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/helpers.lua b/helpers.lua
index 9b858cb..dc6a234 100644
--- a/helpers.lua
+++ b/helpers.lua
@@ -1,11 +1,18 @@
local _, NS = ...
local LibStub = LibStub
+local type = type
+local next = next
+local pairs = pairs
+local wipe = wipe
+local getmetatable = getmetatable
+local setmetatable = setmetatable
local RetrieveCorpse = RetrieveCorpse -- Resurrects when the player is standing near its corpse.
local UnitIsDeadOrGhost = UnitIsDeadOrGhost
+local format = format
-local sformat = string.format
local mfloor = math.floor
+local mmax = math.max
local After = C_Timer.After
@@ -21,19 +28,56 @@ NS.UpdateSize = function(frame, text)
end
NS.UpdateFont = function(frame)
- frame:SetFont(LSM:Fetch("font", AutoBodyRes.db.global.font), AutoBodyRes.db.global.fontsize, "THINOUTLINE")
+ frame:SetFont(LSM:Fetch("font", NS.db.global.font), NS.db.global.fontsize, "OUTLINE")
+end
+
+NS.secondsToMinutes = function(seconds)
+ return seconds / SECONDS_PER_MIN
+end
+
+NS.minutesToSeconds = function(minutes)
+ return minutes * SECONDS_PER_MIN
+end
+
+function ConvertSecondsToUnits(timestamp)
+ timestamp = mmax(timestamp, 0)
+ local days = mfloor(timestamp / SECONDS_PER_DAY)
+ timestamp = timestamp - (days * SECONDS_PER_DAY)
+ local hours = mfloor(timestamp / SECONDS_PER_HOUR)
+ timestamp = timestamp - (hours * SECONDS_PER_HOUR)
+ local minutes = mfloor(timestamp / SECONDS_PER_MIN)
+ timestamp = timestamp - (minutes * SECONDS_PER_MIN)
+ local seconds = mfloor(timestamp)
+ local milliseconds = timestamp - seconds
+ return {
+ days = days,
+ hours = hours,
+ minutes = minutes,
+ seconds = seconds,
+ milliseconds = milliseconds,
+ }
+end
+
+NS.secondsToClock = function(seconds, displayZeroHours)
+ local units = ConvertSecondsToUnits(seconds)
+ if units.hours > 0 or displayZeroHours then
+ return format(HOURS_MINUTES_SECONDS, units.hours, units.minutes, units.seconds)
+ else
+ return format(MINUTES_SECONDS, units.minutes, units.seconds)
+ end
end
NS.getSeconds = function(time)
- return time % 60
+ return time % SECONDS_PER_MIN
end
NS.getMinutes = function(time)
- return mfloor(time / 60)
+ return mfloor(time / SECONDS_PER_MIN)
end
NS.formatTime = function(time)
- return sformat("%02d:%02d", NS.getMinutes(time), NS.getSeconds(time))
+ return NS.secondsToClock(time, false)
+ -- return sformat("%02d:%02d", NS.getMinutes(time), NS.getSeconds(time))
end
NS.RetrieveBody = function()
@@ -44,3 +88,88 @@ NS.RetrieveBody = function()
end
end)
end
+
+-- Copies table values from src to dst if they don't exist in dst
+NS.CopyDefaults = function(src, dst)
+ if type(src) ~= "table" then
+ return {}
+ end
+
+ if type(dst) ~= "table" then
+ dst = {}
+ end
+
+ for k, v in pairs(src) do
+ if type(v) == "table" then
+ dst[k] = NS.CopyDefaults(v, dst[k])
+ elseif type(v) ~= type(dst[k]) then
+ dst[k] = v
+ end
+ end
+
+ return dst
+end
+
+NS.CopyTable = function(src, dest)
+ -- Handle non-tables and previously-seen tables.
+ if type(src) ~= "table" then
+ return src
+ end
+
+ if dest and dest[src] then
+ return dest[src]
+ end
+
+ -- New table; mark it as seen an copy recursively.
+ local s = dest or {}
+ local res = {}
+ s[src] = res
+
+ for k, v in next, src do
+ res[NS.CopyTable(k, s)] = NS.CopyTable(v, s)
+ end
+
+ return setmetatable(res, getmetatable(src))
+end
+
+-- Cleanup savedvariables by removing table values in src that no longer
+-- exists in table dst (default settings)
+NS.CleanupDB = function(src, dst)
+ for key, value in pairs(src) do
+ if dst[key] == nil then
+ -- HACK: offsetsXY are not set in DEFAULT_SETTINGS but sat on demand instead to save memory,
+ -- which causes nil comparison to always be true here, so always ignore these for now
+ if key ~= "offsetsX" and key ~= "offsetsY" and key ~= "version" then
+ src[key] = nil
+ end
+ elseif type(value) == "table" then
+ if key ~= "disabledCategories" and key ~= "categoryTextures" then -- also sat on demand
+ dst[key] = NS.CleanupDB(value, dst[key])
+ end
+ end
+ end
+ return dst
+end
+
+-- Pool for reusing tables. (Garbage collector isn't ran in combat unless max garbage is reached, which causes fps drops)
+do
+ local pool = {}
+
+ NS.NewTable = function()
+ local t = next(pool) or {}
+ pool[t] = nil -- remove from pool
+ return t
+ end
+
+ NS.RemoveTable = function(tbl)
+ if tbl then
+ pool[wipe(tbl)] = true -- add to pool, wipe returns pointer to tbl here
+ end
+ end
+
+ NS.ReleaseTables = function()
+ if next(pool) then
+ pool = {}
+ end
+ end
+end
diff --git a/interface.lua b/interface.lua
index f16c394..8e2a31d 100644
--- a/interface.lua
+++ b/interface.lua
@@ -17,18 +17,18 @@ function Interface:MakeMoveable(frame)
frame:SetMovable(true)
frame:RegisterForDrag("LeftButton")
frame:SetScript("OnDragStart", function(f)
- if AutoBodyRes.db.global.lock == false then
+ if NS.db.global.lock == false then
f:StartMoving()
end
end)
frame:SetScript("OnDragStop", function(f)
- if AutoBodyRes.db.global.lock == false then
+ if NS.db.global.lock == false then
f:StopMovingOrSizing()
local a, _, b, c, d = f:GetPoint()
- AutoBodyRes.db.global.position[1] = a
- AutoBodyRes.db.global.position[2] = b
- AutoBodyRes.db.global.position[3] = c
- AutoBodyRes.db.global.position[4] = d
+ NS.db.global.position[1] = a
+ NS.db.global.position[2] = b
+ NS.db.global.position[3] = c
+ NS.db.global.position[4] = d
end
end)
end
@@ -44,12 +44,14 @@ end
function Interface:AddControls(frame)
frame:EnableMouse(true)
frame:SetScript("OnMouseUp", function(_, btn)
- if btn == "RightButton" then
- LibStub("AceConfigDialog-3.0"):Open(AddonName)
+ if NS.db.global.lock == false then
+ if btn == "RightButton" then
+ LibStub("AceConfigDialog-3.0"):Open(AddonName)
+ end
end
end)
- if AutoBodyRes.db.global.lock then
+ if NS.db.global.lock then
self:StopMovement(frame)
else
self:MakeMoveable(frame)
@@ -116,20 +118,15 @@ function Interface:CreateInterface()
local TextFrame = CreateFrame("Frame", AddonName .. "InterfaceTextFrame", UIParent)
TextFrame:SetClampedToScreen(true)
TextFrame:SetPoint(
- AutoBodyRes.db.global.position[1],
+ NS.db.global.position[1],
UIParent,
- AutoBodyRes.db.global.position[2],
- AutoBodyRes.db.global.position[3],
- AutoBodyRes.db.global.position[4]
+ NS.db.global.position[2],
+ NS.db.global.position[3],
+ NS.db.global.position[4]
)
local Text = TextFrame:CreateFontString(nil, "OVERLAY")
- Text:SetTextColor(
- AutoBodyRes.db.global.color.r,
- AutoBodyRes.db.global.color.g,
- AutoBodyRes.db.global.color.b,
- AutoBodyRes.db.global.color.a
- )
+ Text:SetTextColor(NS.db.global.color.r, NS.db.global.color.g, NS.db.global.color.b, NS.db.global.color.a)
Text:SetShadowOffset(0, 0)
Text:SetShadowColor(0, 0, 0, 1)
Text:SetJustifyH("CENTER")
diff --git a/libs/LibChangelog/CHANGELOG.md b/libs/LibChangelog/CHANGELOG.md
new file mode 100644
index 0000000..693e070
--- /dev/null
+++ b/libs/LibChangelog/CHANGELOG.md
@@ -0,0 +1,8 @@
+# LibChangelog
+
+## [1.0.2](https://github.com/BullseiWoWAddons/LibChangelog/tree/1.0.2) (2023-04-04)
+[Full Changelog](https://github.com/BullseiWoWAddons/LibChangelog/compare/1.0.1...1.0.2) [Previous Releases](https://github.com/BullseiWoWAddons/LibChangelog/releases)
+
+- bump version
+- Update setttings and fix error in wotlk
+- Update README.md
\ No newline at end of file
diff --git a/libs/LibChangelog/LibChangelog.lua b/libs/LibChangelog/LibChangelog.lua
new file mode 100644
index 0000000..d605f24
--- /dev/null
+++ b/libs/LibChangelog/LibChangelog.lua
@@ -0,0 +1,187 @@
+--- LibChangelog
+-- Provides an way to create a simple ingame frame to show a changelog
+
+
+
+local _, Data = ...
+local L = Data.L
+
+
+local MAJOR, MINOR = "LibChangelog", 1
+local LibChangelog = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not LibChangelog then return end
+
+
+-- Lua APIs
+local pcall, error, type, pairs = pcall, error, type, pairs
+
+
+
+
+local NEW_MESSAGE_FONTS = {
+ version = GameFontNormalHuge,
+ title = GameFontNormal,
+ text = GameFontHighlight
+}
+
+local VIEWED_MESSAGE_FONTS = {
+ version = GameFontDisableHuge,
+ title = GameFontDisable,
+ text = GameFontDisable
+}
+
+function LibChangelog:Register(addonName, changelogTable, savedVariablesTable, lastReadVersionKey, onlyShowWhenNewVersionKey, texts)
+
+ if self[addonName] then return error("LibChangelog: '"..addonName.."' already registered", 2) end
+
+
+ self[addonName] = {
+ changelogTable = changelogTable,
+ savedVariablesTable = savedVariablesTable,
+ lastReadVersionKey = lastReadVersionKey,
+ onlyShowWhenNewVersionKey = onlyShowWhenNewVersionKey,
+ texts = texts or {}
+ }
+end
+
+function LibChangelog:CreateString(frame, text, font, offset)
+ local entry = frame.scrollChild:CreateFontString(nil, "ARTWORK")
+
+ if offset == nil then
+ offset = -5
+ end
+
+
+ --print("ScrollChild width", frame.scrollChild:GetWidth())
+ --print("scrollBar width", frame.scrollBar:GetWidth())
+ -- frame.scrollBar:GetWidth() == frame.scrollChild:GetWidth()
+
+ entry:SetFontObject(font or "GameFontNormal")
+ entry:SetText(text)
+ entry:SetJustifyH("LEFT")
+ entry:SetWidth(frame.scrollBar:GetWidth())
+
+ if frame.previous then
+ entry:SetPoint("TOPLEFT", frame.previous, "BOTTOMLEFT", 0, offset)
+ else
+ entry:SetPoint("TOPLEFT", frame.scrollChild, "TOPLEFT", -5)
+ end
+
+ frame.previous = entry
+
+ return entry
+end
+
+-- Did this just to get nice alignment on the bulleted entries (otherwise the text wrapped below the bulle
+
+function LibChangelog:CreateBulletedListEntry(frame, text, font, offset)
+ local bullet = self:CreateString(frame, "- ", font, offset)
+
+ local bulletWidth = 16
+
+ bullet:SetWidth(bulletWidth)
+ bullet:SetJustifyV("TOP")
+
+ local entry = self:CreateString(frame, text, font, offset)
+ entry:SetPoint("TOPLEFT", bullet, "TOPRIGHT")
+ entry:SetWidth(frame.scrollBar:GetWidth() - bulletWidth)
+
+ bullet:SetHeight(entry:GetStringHeight())
+
+ frame.previous = bullet
+ return bullet
+end
+
+function LibChangelog:ShowChangelog(addonName)
+ local fonts = NEW_MESSAGE_FONTS
+
+ local addonData = self[addonName]
+
+ if not addonData then return error("LibChangelog: '"..addonName.. "' was not registered. Please use :Register() first", 2) end
+
+ local firstEntry = addonData.changelogTable[1] --firstEntry contains the newest Version
+
+ local addonSavedVariablesTable = addonData.savedVariablesTable
+
+ if addonData.lastReadVersionKey and addonSavedVariablesTable[addonData.lastReadVersionKey] and firstEntry.Version <= addonSavedVariablesTable[addonData.lastReadVersionKey] and addonSavedVariablesTable[addonData.onlyShowWhenNewVersionKey] then return end
+
+
+ if not addonData.frame then
+
+ local frame = CreateFrame("Frame", nil, UIParent, "ButtonFrameTemplate")
+ ButtonFrameTemplate_HidePortrait(frame)
+ if frame.SetTitle then
+ frame:SetTitle(addonData.texts.title or addonName.." News")
+ else
+ --workaround for TBCC
+ frame.TitleText:SetText(addonData.texts.title or addonName.." News")
+ end
+ frame.Inset:SetPoint("TOPLEFT", 4, -25)
+
+ -- frame:EnableMouse(true)
+
+ frame:SetSize(500, 500)
+ frame:SetPoint("CENTER")
+ -- frame:SetMovable(true)
+ -- frame:RegisterForDrag("LeftButton")
+ -- frame:SetScript("OnDragStart", frame.StartMoving)
+ -- frame:SetScript("OnDragStop", frame.StopMovingOrSizing)
+
+ frame.scrollBar = CreateFrame("ScrollFrame", nil, frame.Inset, "UIPanelScrollFrameTemplate")
+ frame.scrollBar:SetPoint("TOPLEFT", 10, -6)
+ frame.scrollBar:SetPoint("BOTTOMRIGHT", -27, 6)
+
+ frame.scrollChild = CreateFrame("Frame")
+ frame.scrollChild:SetSize(1, 1) -- it doesnt seem to matter how big it is, the only thing that not works is setting the height to really high number, then you can scroll forever
+
+ frame.scrollBar:SetScrollChild(frame.scrollChild)
+
+ frame.CheckButton = CreateFrame("CheckButton", nil, frame, "UICheckButtonTemplate")
+ frame.CheckButton:SetChecked(addonSavedVariablesTable[addonData.onlyShowWhenNewVersionKey])
+ frame.CheckButton:SetFrameStrata("HIGH")
+ frame.CheckButton:SetSize(20, 20)
+ frame.CheckButton:SetScript("OnClick", function(self)
+ local isChecked = self:GetChecked()
+ addonSavedVariablesTable[addonData.onlyShowWhenNewVersionKey] = isChecked
+ frame.CheckButton:SetChecked(isChecked)
+ end)
+ frame.CheckButton:SetPoint("LEFT", frame, "BOTTOMLEFT", 10, 13)
+ if frame.CheckButton.text then
+ frame.CheckButton.text:SetText(addonData.texts.onlyShowWhenNewVersion or "Only Show after next update")
+ elseif frame.CheckButton.Text
+ then frame.CheckButton.Text:SetText(addonData.texts.onlyShowWhenNewVersion or "Only Show after next update")
+ end
+
+ addonData.frame = frame
+ end
+
+
+ for i = 1, #addonData.changelogTable do
+ local versionEntry = addonData.changelogTable[i]
+
+ if addonData.lastReadVersionKey and addonSavedVariablesTable[addonData.lastReadVersionKey] and addonSavedVariablesTable[addonData.lastReadVersionKey] >= versionEntry.Version then
+ fonts = VIEWED_MESSAGE_FONTS
+ end
+
+ -- Add version string
+ self:CreateString(addonData.frame, versionEntry.Version, fonts.version, -30) --add a nice spacing between the version header and the previous text
+
+ if versionEntry.General then
+ self:CreateString(addonData.frame, versionEntry.General, fonts.text)
+ end
+
+ if versionEntry.Sections then
+ for i = 1, #versionEntry.Sections do
+ local section = versionEntry.Sections[i]
+ self:CreateString(addonData.frame, section.Header, fonts.title, -8)
+ local entries = section.Entries
+ for j = 1, #entries do
+ self:CreateBulletedListEntry(addonData.frame, entries[j], fonts.text)
+ end
+ end
+ end
+ end
+
+ addonSavedVariablesTable[addonData.lastReadVersionKey] = firstEntry.Version
+end
\ No newline at end of file
diff --git a/libs/LibChangelog/LibChangelog.toc b/libs/LibChangelog/LibChangelog.toc
new file mode 100644
index 0000000..2679be1
--- /dev/null
+++ b/libs/LibChangelog/LibChangelog.toc
@@ -0,0 +1,8 @@
+## Interface: 90005
+## Title: LibChangelog
+## Version: 1.0.2
+## Author: Bullsei
+
+## X-Curse-Project-ID: 497698
+
+LibChangelog.xml
\ No newline at end of file
diff --git a/Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml b/libs/LibChangelog/LibChangelog.xml
similarity index 81%
rename from Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml
rename to libs/LibChangelog/LibChangelog.xml
index 2668fb0..23fc732 100644
--- a/Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml
+++ b/libs/LibChangelog/LibChangelog.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/libs/LibChangelog/README.md b/libs/LibChangelog/README.md
new file mode 100644
index 0000000..73127bf
--- /dev/null
+++ b/libs/LibChangelog/README.md
@@ -0,0 +1,3 @@
+# LibChangelog
+
+https://github.com/BullseiWoWAddons/LibChangelog/wiki/How-to-use
diff --git a/options.lua b/options.lua
index 7565121..4694463 100644
--- a/options.lua
+++ b/options.lua
@@ -1,9 +1,24 @@
local AddonName, NS = ...
-local AutoBodyRes = LibStub("AceAddon-3.0"):GetAddon(AddonName)
-
+local LibStub = LibStub
+local CopyTable = CopyTable
+local next = next
local IsInInstance = IsInInstance
+---@type AutoBodyRes
+local AutoBodyRes = NS.AutoBodyRes
+local AutoBodyResFrame = NS.AutoBodyRes.frame
+
+local Options = {}
+NS.Options = Options
+
+local DEAD_EVENTS = {
+ "PLAYER_DEAD",
+ "PLAYER_SKINNED",
+ "CORPSE_IN_RANGE",
+ "RESURRECT_REQUEST",
+}
+
NS.AceConfig = {
name = AddonName,
type = "group",
@@ -12,8 +27,9 @@ NS.AceConfig = {
name = "Lock the text into place",
type = "toggle",
width = "double",
+ order = 1,
set = function(_, val)
- AutoBodyRes.db.global.lock = val
+ NS.db.global.lock = val
if val then
NS.Interface:Lock(NS.Interface.textFrame)
else
@@ -21,7 +37,7 @@ NS.AceConfig = {
end
end,
get = function(_)
- return AutoBodyRes.db.global.lock
+ return NS.db.global.lock
end,
},
test = {
@@ -29,8 +45,9 @@ NS.AceConfig = {
desc = "Only works outside of an instance.",
type = "toggle",
width = "double",
+ order = 2,
set = function(_, val)
- AutoBodyRes.db.global.test = val
+ NS.db.global.test = val
if IsInInstance() == false then
if val then
NS.Interface.text:SetText("CAN BODY RES NOW")
@@ -45,7 +62,7 @@ NS.AceConfig = {
end
end,
get = function(_)
- return AutoBodyRes.db.global.test
+ return NS.db.global.test
end,
},
release = {
@@ -53,11 +70,12 @@ NS.AceConfig = {
desc = "Auto releases your body upon death.",
type = "toggle",
width = "double",
+ order = 3,
set = function(_, val)
- AutoBodyRes.db.global.release = val
+ NS.db.global.release = val
end,
get = function(_)
- return AutoBodyRes.db.global.release
+ return NS.db.global.release
end,
},
resurrect = {
@@ -65,11 +83,12 @@ NS.AceConfig = {
desc = "Auto accepts resurrection from a friend, spell, or your from being in-range of your body.",
type = "toggle",
width = "double",
+ order = 4,
set = function(_, val)
- AutoBodyRes.db.global.resurrect = val
+ NS.db.global.resurrect = val
end,
get = function(_)
- return AutoBodyRes.db.global.resurrect
+ return NS.db.global.resurrect
end,
},
onlypvp = {
@@ -77,78 +96,141 @@ NS.AceConfig = {
desc = "Toggling this feature off will make it work outside of battlegrounds",
type = "toggle",
width = "double",
+ order = 5,
set = function(_, val)
- AutoBodyRes.db.global.onlypvp = val
+ NS.db.global.onlypvp = val
if IsInInstance() == false then
if val == false then
- AutoBodyRes:PlayerDeadEvents()
+ FrameUtil.RegisterFrameForEvents(AutoBodyResFrame, DEAD_EVENTS)
else
- AutoBodyRes:UnregisterEvent("PLAYER_DEAD")
- AutoBodyRes:UnregisterEvent("PLAYER_SKINNED")
- AutoBodyRes:UnregisterEvent("CORPSE_IN_RANGE")
- AutoBodyRes:UnregisterEvent("RESURRECT_REQUEST")
+ FrameUtil.UnregisterFrameForEvents(AutoBodyResFrame, DEAD_EVENTS)
end
end
end,
get = function(_)
- return AutoBodyRes.db.global.onlypvp
+ return NS.db.global.onlypvp
end,
},
fontsize = {
type = "range",
name = "Font Size",
width = "double",
+ order = 6,
min = 1,
max = 500,
step = 1,
set = function(_, val)
- AutoBodyRes.db.global.fontsize = val
+ NS.db.global.fontsize = val
NS.UpdateFont(NS.Interface.text)
NS.UpdateSize(NS.Interface.textFrame, NS.Interface.text)
end,
get = function(_)
- return AutoBodyRes.db.global.fontsize
+ return NS.db.global.fontsize
end,
},
font = {
type = "select",
name = "Font",
width = "double",
+ order = 7,
dialogControl = "LSM30_Font",
values = AceGUIWidgetLSMlists.font,
set = function(_, val)
- AutoBodyRes.db.global.font = val
+ NS.db.global.font = val
NS.UpdateFont(NS.Interface.text)
NS.UpdateSize(NS.Interface.textFrame, NS.Interface.text)
end,
get = function(_)
- return AutoBodyRes.db.global.font
+ return NS.db.global.font
end,
},
color = {
type = "color",
name = "Color",
width = "double",
+ order = 8,
hasAlpha = true,
set = function(_, val1, val2, val3, val4)
- AutoBodyRes.db.global.color.r = val1
- AutoBodyRes.db.global.color.g = val2
- AutoBodyRes.db.global.color.b = val3
- AutoBodyRes.db.global.color.a = val4
+ NS.db.global.color.r = val1
+ NS.db.global.color.g = val2
+ NS.db.global.color.b = val3
+ NS.db.global.color.a = val4
NS.Interface.text:SetTextColor(val1, val2, val3, val4)
end,
get = function(_)
- return AutoBodyRes.db.global.color.r,
- AutoBodyRes.db.global.color.g,
- AutoBodyRes.db.global.color.b,
- AutoBodyRes.db.global.color.a
+ return NS.db.global.color.r, NS.db.global.color.g, NS.db.global.color.b, NS.db.global.color.a
+ end,
+ },
+ debug = {
+ name = "Toggle debug mode",
+ desc = "Turning this feature on prints debug messages to the chat window.",
+ type = "toggle",
+ width = "full",
+ order = 99,
+ set = function(_, val)
+ NS.db.global.debug = val
+ end,
+ get = function(_)
+ return NS.db.global.debug
+ end,
+ },
+ reset = {
+ name = "Reset Everything",
+ type = "execute",
+ width = "normal",
+ order = 100,
+ func = function()
+ AutoBodyResDB = CopyTable(NS.DefaultDatabase)
+ NS.db = CopyTable(NS.DefaultDatabase)
+ NS.UpdateFont(NS.Interface.text)
+ NS.UpdateSize(NS.Interface.textFrame, NS.Interface.text)
end,
},
},
}
-function AutoBodyRes:SetupOptions()
+function Options:SlashCommands(message)
+ if message == "toggle lock" then
+ if NS.db.global.general.lock == false then
+ NS.db.global.general.lock = true
+ else
+ NS.db.global.general.lock = false
+ end
+ else
+ LibStub("AceConfigDialog-3.0"):Open(AddonName)
+ end
+end
+
+function Options:Setup()
LibStub("AceConfig-3.0"):RegisterOptionsTable(AddonName, NS.AceConfig)
LibStub("AceConfigDialog-3.0"):AddToBlizOptions(AddonName, AddonName)
+
+ SLASH_ABR1 = AddonName
+ SLASH_ABR2 = "/abr"
+
+ function SlashCmdList.ABR(message)
+ self:SlashCommands(message)
+ end
+end
+
+function AutoBodyRes:ADDON_LOADED(addon)
+ if addon == AddonName then
+ AutoBodyResFrame:UnregisterEvent("ADDON_LOADED")
+
+ AutoBodyResDB = AutoBodyResDB and next(AutoBodyResDB) ~= nil and AutoBodyResDB or {}
+
+ -- Copy any settings from default if they don't exist in current profile
+ NS.CopyDefaults(NS.DefaultDatabase, AutoBodyResDB)
+
+ -- Reference to active db profile
+ -- Always use this directly or reference will be invalid
+ NS.db = AutoBodyResDB
+
+ -- Remove table values no longer found in default settings
+ NS.CleanupDB(AutoBodyResDB, NS.DefaultDatabase)
+
+ Options:Setup()
+ end
end
+AutoBodyResFrame:RegisterEvent("ADDON_LOADED")