Compare commits
25 Commits
7ae482ed73
...
1.1.1
Author | SHA1 | Date | |
---|---|---|---|
717a8ee015 | |||
b9a671b0f2 | |||
b43608b724 | |||
f5b9b973e3 | |||
0638896bc3 | |||
7df8ecb582 | |||
3bd12c8ca8 | |||
38b5dbccb1 | |||
24e56078bd | |||
10d35da8e0 | |||
b7a184b26b | |||
f1b1a384d4 | |||
4c3913ca3f | |||
2b1baaca36 | |||
038e3a70af | |||
1e014b2d5b | |||
ac32b1fd75 | |||
c7b843ca03 | |||
8b310197fc | |||
9520269857 | |||
29cd686eec | |||
94408916e0 | |||
b7eb0b1cdf | |||
6a4cc91413 | |||
a6d570c553 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.zip
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "Meta"]
|
||||
path = Meta
|
||||
url = https://git.site.quack-lab.dev/dave/wow_Meta
|
5
.luacheckrc
Symbolic link
5
.luacheckrc
Symbolic link
@@ -0,0 +1,5 @@
|
||||
globals = { "CykaPersistentData", "CreateFrame", "GetItemInfo" }
|
||||
unused_args = false
|
||||
max_line_length = 150
|
||||
exclude_files = { "Meta/" }
|
||||
global = false
|
11
.luarc.json
Symbolic link
11
.luarc.json
Symbolic link
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"workspace": {
|
||||
"library": [
|
||||
"./Meta"
|
||||
]
|
||||
},
|
||||
"diagnostics.disable": [
|
||||
"unused-local",
|
||||
"unused-vararg"
|
||||
]
|
||||
}
|
12
ActionBarSaverDaved.toc
Normal file
12
ActionBarSaverDaved.toc
Normal file
@@ -0,0 +1,12 @@
|
||||
## Interface: 70300
|
||||
## Title: ActionBarSaver: Daved
|
||||
## Version: 1.1.1
|
||||
## Notes: Manage, save, restore, import and export action bar and keybind profiles
|
||||
## Author: Phat phuck dave
|
||||
## SavedVariables: ActionBarSaverDaved, KeybindSaverDaved
|
||||
|
||||
B64.lua
|
||||
Constants.lua
|
||||
Main.lua
|
||||
Actions.lua
|
||||
KeybindSaver.lua
|
@@ -1,10 +0,0 @@
|
||||
## Interface: 40400
|
||||
## Title: ActionBarSaver: Reloaded
|
||||
## Version: 1.0.7
|
||||
## Notes: Manage, save, and restore action bar profiles
|
||||
## Author: Voodoomoose
|
||||
## SavedVariables: ActionBarSaverReloaded
|
||||
|
||||
Constants.lua
|
||||
Main.lua
|
||||
Actions.lua
|
685
Actions.lua
685
Actions.lua
@@ -1,291 +1,542 @@
|
||||
local ADDON_LOADED, shared = ...
|
||||
local typeMap = {
|
||||
spell = "S",
|
||||
item = "I",
|
||||
macro = "M",
|
||||
companion = "C",
|
||||
equipmentset = "E",
|
||||
summonmount = "U",
|
||||
}
|
||||
local inverseTypeMap = {
|
||||
S = "spell",
|
||||
I = "item",
|
||||
M = "macro",
|
||||
C = "companion",
|
||||
E = "equipmentset",
|
||||
U = "summonmount",
|
||||
}
|
||||
|
||||
---@param setName string
|
||||
---@return nil
|
||||
local function PickupEquipmentSet(setName)
|
||||
local setIndex = 0
|
||||
local setIndex = 0
|
||||
|
||||
for i = 1, C_EquipmentSet.GetNumEquipmentSets() do
|
||||
local sn = C_EquipmentSet.GetEquipmentSetInfo(i)
|
||||
for i = 1, C_EquipmentSet.GetNumEquipmentSets() do
|
||||
local sn = C_EquipmentSet.GetEquipmentSetInfo(i)
|
||||
|
||||
if sn == setName then
|
||||
setIndex = i
|
||||
end
|
||||
end
|
||||
if sn == setName then setIndex = i end
|
||||
end
|
||||
|
||||
C_EquipmentSet.PickupEquipmentSet(setIndex)
|
||||
C_EquipmentSet.PickupEquipmentSet(setIndex)
|
||||
end
|
||||
|
||||
local pickupActionButton = {
|
||||
item = PickupItem,
|
||||
spell = PickupSpell,
|
||||
macro = PickupMacro,
|
||||
companion = PickupSpell,
|
||||
equipmentset = PickupEquipmentSet
|
||||
item = PickupItem,
|
||||
spell = PickupSpell,
|
||||
macro = PickupMacro,
|
||||
companion = PickupSpell,
|
||||
equipmentset = PickupEquipmentSet,
|
||||
summonmount = C_MountJournal.Pickup,
|
||||
}
|
||||
|
||||
local function RestoreActionButton(self, index, actionButton)
|
||||
-- Clear the slot
|
||||
if GetActionInfo(index) then
|
||||
PickupAction(index)
|
||||
ClearCursor()
|
||||
end
|
||||
---@param index number
|
||||
---@param actionButton {type: string, id: number|string}
|
||||
---@return boolean, number?
|
||||
local function RestoreActionButton(index, actionButton)
|
||||
if GetActionInfo(index) then
|
||||
PickupAction(index)
|
||||
ClearCursor()
|
||||
end
|
||||
|
||||
if not actionButton then
|
||||
return true, nil
|
||||
end
|
||||
if not actionButton then return true, nil end
|
||||
|
||||
local aliases = ActionBarSaverReloaded.spellAliases[actionButton.id] or {}
|
||||
local ids = Array.insert(aliases, actionButton.id, 1)
|
||||
local aliases = ActionBarSaverDaved.spellAliases[actionButton.id] or {}
|
||||
table.insert(aliases, actionButton.id)
|
||||
|
||||
for _, id in ipairs(ids) do
|
||||
pickupActionButton[actionButton.type](id)
|
||||
for _, id in ipairs(aliases) do
|
||||
pickupActionButton[actionButton.type](id)
|
||||
|
||||
if GetCursorInfo() == actionButton.type then
|
||||
PlaceAction(index)
|
||||
return true, id
|
||||
end
|
||||
if GetCursorInfo() == actionButton.type then
|
||||
PlaceAction(index)
|
||||
return true, id
|
||||
end
|
||||
|
||||
ClearCursor()
|
||||
end
|
||||
ClearCursor()
|
||||
end
|
||||
|
||||
return false
|
||||
return false
|
||||
end
|
||||
|
||||
local function IsMacro(actionButton)
|
||||
return actionButton and actionButton.type == "macro"
|
||||
---@param index number
|
||||
---@return boolean
|
||||
local function ClearActionButton(index)
|
||||
if not index then return false end
|
||||
PickupAction(index)
|
||||
ClearCursor()
|
||||
return true
|
||||
end
|
||||
|
||||
---@param actionButton {type: string, id: number|string}
|
||||
---@return boolean
|
||||
local function IsMacro(actionButton) return actionButton and actionButton.type == "macro" end
|
||||
|
||||
---@return table<string, number>
|
||||
local function GetMacroDuplicates()
|
||||
local t = {}
|
||||
local duplicates = {}
|
||||
local t = {}
|
||||
local duplicates = {}
|
||||
|
||||
for i = 1, MAX_MACROS do
|
||||
local macroName = GetMacroInfo(i)
|
||||
for i = 1, MAX_MACROS do
|
||||
local macroName = GetMacroInfo(i)
|
||||
|
||||
if macroName then
|
||||
if not t[macroName] then
|
||||
t[macroName] = 1
|
||||
else
|
||||
t[macroName] = t[macroName] + 1
|
||||
duplicates[macroName] = t[macroName]
|
||||
end
|
||||
end
|
||||
end
|
||||
if macroName then
|
||||
if not t[macroName] then
|
||||
t[macroName] = 1
|
||||
else
|
||||
t[macroName] = t[macroName] + 1
|
||||
duplicates[macroName] = t[macroName]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return duplicates
|
||||
return duplicates
|
||||
end
|
||||
|
||||
---@param warnings table<string, number>
|
||||
---@param macroName string
|
||||
---@param usages number
|
||||
---@return nil
|
||||
local function AddWarning(warnings, macroName, usages)
|
||||
table.insert(warnings, string.format("Warning: Found %d macros named '%s'. Consider renaming them to avoid issues",
|
||||
usages, macroName))
|
||||
table.insert(
|
||||
warnings,
|
||||
string.format("Warning: Found %d macros named '%s'. Consider renaming them to avoid issues", usages, macroName)
|
||||
)
|
||||
end
|
||||
|
||||
function SaveSet(setName)
|
||||
print("ABS SaveSet")
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
---@param setName string
|
||||
---@return nil
|
||||
function SaveActionbarSet(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
|
||||
local duplicates = GetMacroDuplicates()
|
||||
local set = {}
|
||||
local warnings = {}
|
||||
local duplicates = GetMacroDuplicates()
|
||||
---@type table<number, {type: string, id: number|string}>
|
||||
local set = {}
|
||||
---@type string[]
|
||||
local warnings = {}
|
||||
|
||||
for i = 1, MAX_ACTION_BUTTONS do
|
||||
local type, id = GetActionInfo(i)
|
||||
for i = 1, MAX_ACTION_BUTTONS do
|
||||
local type, id = GetActionInfo(i)
|
||||
|
||||
if type == "macro" then
|
||||
-- use macro name as the ID
|
||||
id = GetMacroInfo(id)
|
||||
if duplicates[id] then
|
||||
AddWarning(warnings, id, duplicates[id])
|
||||
end
|
||||
end
|
||||
if type == "macro" then
|
||||
-- use macro name as the ID
|
||||
id = GetMacroInfo(id)
|
||||
if duplicates[id] then AddWarning(warnings, id, duplicates[id]) end
|
||||
end
|
||||
|
||||
if type and id then
|
||||
set[i] = type and {
|
||||
type = type,
|
||||
id = id
|
||||
}
|
||||
end
|
||||
end
|
||||
if type and id then set[i] = type and {
|
||||
type = type,
|
||||
id = id,
|
||||
} end
|
||||
end
|
||||
|
||||
ActionBarSaverReloaded.sets[setName] = set
|
||||
print(string.format("Saved set '%s'!", setName))
|
||||
Array.iter(warnings, function(warning)
|
||||
print(warning)
|
||||
end)
|
||||
ActionBarSaverDaved.sets[setName] = set
|
||||
print(string.format("Saved set '%s'!", setName))
|
||||
for _, warning in ipairs(warnings) do
|
||||
print(warning)
|
||||
end
|
||||
end
|
||||
|
||||
function RestoreSet(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
---@param setName string
|
||||
---@return nil
|
||||
function RestoreActionbarSet(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
|
||||
local set = ActionBarSaverReloaded.sets[setName]
|
||||
local set = ActionBarSaverDaved.sets[setName]
|
||||
|
||||
if not set then
|
||||
print(string.format("No set with the name '%s' exists", setName))
|
||||
return
|
||||
end
|
||||
if InCombatLockdown() then
|
||||
print("Cannot restore sets while in combat")
|
||||
return
|
||||
end
|
||||
if not set then
|
||||
print(string.format("No set with the name '%s' exists", setName))
|
||||
return
|
||||
end
|
||||
if InCombatLockdown() then
|
||||
print("Cannot restore sets while in combat")
|
||||
return
|
||||
end
|
||||
|
||||
local duplicates = GetMacroDuplicates()
|
||||
local messages = {}
|
||||
local duplicates = GetMacroDuplicates()
|
||||
local messages = {}
|
||||
|
||||
-- Start with an empty cursor
|
||||
ClearCursor()
|
||||
-- Start with an empty cursor
|
||||
ClearCursor()
|
||||
|
||||
for i = 1, MAX_ACTION_BUTTONS do
|
||||
local actionButton = set[i]
|
||||
for i = 1, MAX_ACTION_BUTTONS do
|
||||
local actionButton = set[i]
|
||||
if actionButton then
|
||||
if IsMacro(actionButton) and duplicates[actionButton.id] then
|
||||
---@cast actionButton {type: string, id: string}
|
||||
AddWarning(messages, actionButton.id, duplicates[actionButton.id])
|
||||
end
|
||||
|
||||
if IsMacro(actionButton) and duplicates[actionButton.id] then
|
||||
AddWarning(messages, actionButton.id, duplicates[actionButton.id])
|
||||
end
|
||||
local succeeded, restoredID = RestoreActionButton(i, actionButton)
|
||||
if not succeeded or not restoredID then
|
||||
table.insert(
|
||||
messages,
|
||||
string.format(
|
||||
"Error: Unable to restore %s with id [%s] to slot %d",
|
||||
actionButton.type,
|
||||
actionButton.id or "",
|
||||
i
|
||||
)
|
||||
)
|
||||
elseif actionButton and restoredID ~= actionButton.id then
|
||||
table.insert(
|
||||
messages,
|
||||
string.format(
|
||||
"Info: Restored spell %d (%s) in place of spell %d",
|
||||
restoredID,
|
||||
GetSpellInfo(restoredID),
|
||||
actionButton.id
|
||||
)
|
||||
)
|
||||
end
|
||||
else
|
||||
ClearActionButton(i)
|
||||
end
|
||||
end
|
||||
|
||||
local succeeded, restoredID = RestoreActionButton(self, i, actionButton)
|
||||
if not succeeded then
|
||||
table.insert(messages, string.format("Error: Unable to restore %s with id [%s] to slot %d",
|
||||
actionButton.type, actionButton.id or "", i))
|
||||
elseif actionButton and restoredID ~= actionButton.id then
|
||||
table.insert(messages,
|
||||
string.format("Info: Restored spell %d (%s) in place of spell %d", restoredID, GetSpellInfo(restoredID),
|
||||
actionButton.id))
|
||||
end
|
||||
end
|
||||
|
||||
print(string.format("Restored set '%s'", setName))
|
||||
Array.iter(messages, function(warning)
|
||||
print(warning)
|
||||
end)
|
||||
print(string.format("Restored set '%s'", setName))
|
||||
for _, warning in ipairs(messages) do
|
||||
print(warning)
|
||||
end
|
||||
end
|
||||
|
||||
function DeleteSet(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
---@param setName string
|
||||
---@return nil
|
||||
function DeleteActionbarSet(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
|
||||
if not ActionBarSaverReloaded.sets[setName] then
|
||||
print(string.format("No set with the name '%s' exists", setName))
|
||||
return
|
||||
end
|
||||
if not ActionBarSaverDaved.sets[setName] then
|
||||
print(string.format("No set with the name '%s' exists", setName))
|
||||
return
|
||||
end
|
||||
|
||||
ActionBarSaverReloaded.sets[setName] = nil
|
||||
ActionBarSaverDaved.sets[setName] = nil
|
||||
|
||||
print(string.format("Deleted set '%s'", setName))
|
||||
print(string.format("Deleted set '%s'", setName))
|
||||
end
|
||||
|
||||
function ListSets()
|
||||
local sets = Dict.keysAsArray(ActionBarSaverReloaded.sets)
|
||||
table.sort(sets)
|
||||
local setsStr = table.concat(sets, ", ")
|
||||
---@return nil
|
||||
function ListActionbarSets()
|
||||
local sets = {}
|
||||
for setName, foo in pairs(ActionBarSaverDaved.sets) do
|
||||
sets[#sets + 1] = setName
|
||||
end
|
||||
table.sort(sets)
|
||||
local setsStr = table.concat(sets, ", ")
|
||||
|
||||
print(not Str.nullOrEmpty(setsStr) and setsStr or "No sets found")
|
||||
print(not (not setsStr or setsStr == "") and setsStr or "No sets found")
|
||||
end
|
||||
|
||||
function AliasSpell(args)
|
||||
if not args or args == "" then
|
||||
print("Must provide args in the format 'spellID aliasID'")
|
||||
return
|
||||
end
|
||||
local spellID, aliasID = string.match(args, "(%d+)%s+(%d+)")
|
||||
---@param of string
|
||||
---@param to string
|
||||
---@return nil
|
||||
function AliasSpell(of, to)
|
||||
if not of or not to then
|
||||
print("Must provide args in the format 'spellID aliasID'")
|
||||
return
|
||||
end
|
||||
local ofId = tonumber(of)
|
||||
local toId = tonumber(to)
|
||||
|
||||
spellID = tonumber(spellID)
|
||||
aliasID = tonumber(aliasID)
|
||||
if not (ofId and toId) then
|
||||
print(string.format("Could not parse %s and/or %s to numbers", of, to))
|
||||
return
|
||||
end
|
||||
|
||||
if not (spellID and aliasID) then
|
||||
print(string.format("Could not parse spellID and aliasID from '%s'", args))
|
||||
return
|
||||
end
|
||||
local aliases = ActionBarSaverDaved.spellAliases[ofId] or {}
|
||||
|
||||
local aliases = ActionBarSaverReloaded.spellAliases[spellID] or {}
|
||||
for _, id in ipairs(aliases) do
|
||||
if id == toId then
|
||||
print(string.format("Spell %d is already aliased by %d", ofId, toId))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if Array.contains(aliases, aliasID) then
|
||||
print(string.format("Spell %d is already aliased by %d", spellID, aliasID))
|
||||
return
|
||||
end
|
||||
|
||||
table.insert(aliases, aliasID)
|
||||
ActionBarSaverReloaded.spellAliases[spellID] = aliases
|
||||
|
||||
print(string.format("Added %d as an alias for %d", aliasID, spellID))
|
||||
table.insert(ActionBarSaverDaved.spellAliases[ofId], toId)
|
||||
print(string.format("Added %d as an alias for %d", toId, ofId))
|
||||
end
|
||||
|
||||
function DeleteSpellAliases(spellID)
|
||||
if not spellID or spellID == "" then
|
||||
print("Must provide a valid spellID")
|
||||
return
|
||||
end
|
||||
---@param of string
|
||||
---@return nil
|
||||
function DeleteSpellAliases(of)
|
||||
if not of then
|
||||
print("Must provide a valid spellID")
|
||||
return
|
||||
end
|
||||
|
||||
spellID = tonumber(spellID)
|
||||
local ofId = tonumber(of)
|
||||
|
||||
if not ActionBarSaverReloaded.spellAliases[spellID] then
|
||||
print(string.format("No aliases to remove for spell with ID %d", spellID))
|
||||
return
|
||||
end
|
||||
if not ofId then
|
||||
print(string.format("Could not parse spellID from '%s'", of))
|
||||
return
|
||||
end
|
||||
|
||||
ActionBarSaverReloaded.spellAliases[spellID] = nil
|
||||
if not ActionBarSaverDaved.spellAliases[ofId] then
|
||||
print(string.format("No aliases to remove for spell with ID %d", ofId))
|
||||
return
|
||||
end
|
||||
|
||||
print(string.format("Removed all aliases for spell with ID %d", spellID))
|
||||
ActionBarSaverDaved.spellAliases[ofId] = nil
|
||||
print(string.format("Removed all aliases for spell with ID %d", ofId))
|
||||
end
|
||||
|
||||
---@return nil
|
||||
function ListAliases()
|
||||
local aliases = ActionBarSaverReloaded.spellAliases
|
||||
|
||||
if Dict.isEmpty(aliases) then
|
||||
print("No aliases found")
|
||||
return
|
||||
end
|
||||
|
||||
Dict.iter(ActionBarSaverReloaded.spellAliases, function(spellID, aliases)
|
||||
print(string.format("Spell %d is aliased by: %s", spellID, table.concat(aliases, ", ")))
|
||||
end)
|
||||
for spellID, spellAliases in pairs(ActionBarSaverDaved.spellAliases) do
|
||||
print(string.format("Spell %d is aliased by: %s", spellID, table.concat(spellAliases, ", ")))
|
||||
end
|
||||
end
|
||||
|
||||
function PrintUsage()
|
||||
print("ABS Slash commands")
|
||||
print("/abs save <set> - Saves your current action bar setup under the given <set>")
|
||||
print("/abs restore <set> - Restores the saved <set>")
|
||||
print("/abs delete <set> - Deletes the saved <set>")
|
||||
print("/abs list - Lists all saved sets")
|
||||
print("/abs alias <spellID> <aliasID> - Adds an alias with <aliasID> to <spellID>")
|
||||
print("/abs unalias <spellID> - Removes all aliases associated with <spellID>")
|
||||
print("/abs aliases - List all spell aliases")
|
||||
local importingSet = nil
|
||||
local importExportFrame = CreateFrame("Frame", "ABSImportExportFrame", UIParent)
|
||||
importExportFrame:SetSize(512, 512)
|
||||
importExportFrame:SetPoint("CENTER")
|
||||
importExportFrame:SetFrameStrata("HIGH")
|
||||
importExportFrame:EnableMouse(true)
|
||||
importExportFrame:SetMovable(true)
|
||||
importExportFrame:SetResizable(false)
|
||||
importExportFrame:SetBackdrop({
|
||||
bgFile = "Interface/Tooltips/UI-Tooltip-Background",
|
||||
edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
|
||||
tile = true,
|
||||
tileSize = 4,
|
||||
edgeSize = 4,
|
||||
insets = {
|
||||
left = 4,
|
||||
right = 4,
|
||||
top = 4,
|
||||
bottom = 4,
|
||||
},
|
||||
})
|
||||
importExportFrame:SetBackdropColor(0, 0, 0, 0.8)
|
||||
importExportFrame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
|
||||
|
||||
importExportFrame:SetMovable(true)
|
||||
importExportFrame:EnableMouse(true)
|
||||
importExportFrame:RegisterForDrag("LeftButton")
|
||||
importExportFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
|
||||
importExportFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
|
||||
importExportFrame:SetScript("OnShow", function(self) self:SetScale(1) end)
|
||||
importExportFrame:Hide()
|
||||
|
||||
local importExportFrameTextBox = CreateFrame("EditBox", "ABSImportExportFrameTextBox", importExportFrame)
|
||||
importExportFrameTextBox:SetSize(512, 512)
|
||||
importExportFrameTextBox:SetPoint("TOPLEFT", importExportFrame, "TOPLEFT", 0, 0)
|
||||
importExportFrameTextBox:SetFont("Fonts\\FRIZQT__.ttf", 12)
|
||||
importExportFrameTextBox:SetTextColor(1, 1, 1, 1)
|
||||
importExportFrameTextBox:SetTextInsets(20, 20, 20, 20)
|
||||
importExportFrameTextBox:SetMultiLine(true)
|
||||
importExportFrameTextBox:SetAutoFocus(true)
|
||||
importExportFrameTextBox:SetMaxLetters(1000000)
|
||||
importExportFrameTextBox:SetScript("OnEscapePressed", function(self)
|
||||
importExportFrame:Hide()
|
||||
if importingSet then
|
||||
local lines = { strsplit("\n", self:GetText()) }
|
||||
for _, line in ipairs(lines) do
|
||||
line = strtrim(line)
|
||||
if line ~= "" then ImportActionbarSet(importingSet, line) end
|
||||
end
|
||||
importingSet = nil
|
||||
end
|
||||
end)
|
||||
|
||||
---@param setName string
|
||||
---@return nil
|
||||
function ExportActionbarSet(setName)
|
||||
local set = ActionBarSaverDaved.sets[setName]
|
||||
if not set then
|
||||
print(string.format("No set with the name '%s' exists", setName))
|
||||
return
|
||||
end
|
||||
local macros = {}
|
||||
local stringified = {}
|
||||
for slot, action in pairs(set) do
|
||||
local typeChar = typeMap[action.type]
|
||||
if not typeChar then
|
||||
print(string.format("Unknown action type '%s' in set '%s'", action.type, setName))
|
||||
return
|
||||
end
|
||||
stringified[#stringified + 1] =
|
||||
string.format("%s\\%s\\%s", tostring(slot), tostring(action.id), tostring(typeChar))
|
||||
if typeChar == "M" then
|
||||
local _, _, macro = GetMacroInfo(action.id)
|
||||
if macro then macros[action.id] = macro end
|
||||
end
|
||||
end
|
||||
|
||||
local export = {}
|
||||
for name, macro in pairs(macros) do
|
||||
local content = B64.Encode(macro)
|
||||
export[#export + 1] = string.format("Mž%sž%s", name, content)
|
||||
end
|
||||
export[#export + 1] = table.concat(stringified, "ž")
|
||||
local str = table.concat(export, "\n")
|
||||
importExportFrame:Show()
|
||||
importExportFrameTextBox:SetText(str)
|
||||
importExportFrameTextBox:SetFocus()
|
||||
end
|
||||
|
||||
---@param action {slot: number, id: number|string, type: string}
|
||||
---@return string
|
||||
function FormatAction(action) return string.format("slot: %d, id: %s, type: %s", action.slot, action.id, action.type) end
|
||||
|
||||
---@param action string
|
||||
---@return {slot: number, id: number|string, type: string}
|
||||
function ParseAction(action)
|
||||
local ret = {
|
||||
slot = 0,
|
||||
id = 0,
|
||||
type = "",
|
||||
}
|
||||
|
||||
if not action or action == "" then return ret end
|
||||
action = strtrim(action)
|
||||
---@type string, string, string
|
||||
local slot, id, typeChar = string.match(action, "([^\\]+)\\([^\\]+)\\([^\\]+)")
|
||||
if not typeChar then
|
||||
print(string.format("Unknown action type '%s' for action '%s'", tostring(typeChar), FormatAction(ret)))
|
||||
return ret
|
||||
end
|
||||
local type = inverseTypeMap[typeChar]
|
||||
if not type then
|
||||
print(string.format("Unknown action type '%s' for action '%s'", tostring(typeChar), FormatAction(ret)))
|
||||
return ret
|
||||
end
|
||||
|
||||
local slotNum = tonumber(slot)
|
||||
if not slotNum then
|
||||
print(string.format("Unknown slot '%s' for action '%s'", tostring(slot), FormatAction(ret)))
|
||||
return ret
|
||||
end
|
||||
|
||||
if not id then
|
||||
print(string.format("Unknown id '%s' for action '%s'", tostring(id), FormatAction(ret)))
|
||||
return ret
|
||||
end
|
||||
|
||||
return {
|
||||
slot = slotNum,
|
||||
id = id,
|
||||
type = type,
|
||||
}
|
||||
end
|
||||
|
||||
---@param importString string
|
||||
---@return nil
|
||||
function ImportMacro(importString)
|
||||
if not importString or importString == "" then
|
||||
print("Must provide a valid macro string")
|
||||
return
|
||||
end
|
||||
importString = strtrim(importString)
|
||||
local name, content = string.match(importString, "^Mž([^ž]+)ž([^ž]+)")
|
||||
if not name or not content then
|
||||
print("Error: Invalid macro part format")
|
||||
return
|
||||
end
|
||||
content = strtrim(content)
|
||||
name = strtrim(name)
|
||||
|
||||
local reconstructed = B64.Decode(content)
|
||||
local macroIdx = GetMacroIndexByName(name)
|
||||
if macroIdx == 0 then
|
||||
CreateMacro(name, "Inv_misc_questionmark", "")
|
||||
macroIdx = GetMacroIndexByName(name)
|
||||
end
|
||||
EditMacro(macroIdx, name, nil, reconstructed)
|
||||
print(string.format("Imported macro '%s' with index %d and content '%s'", name, macroIdx, reconstructed))
|
||||
end
|
||||
|
||||
---@param setName string
|
||||
---@param str string
|
||||
---@return nil
|
||||
function ImportActionbarSet(setName, str)
|
||||
if not setName or setName == "" then
|
||||
print("Must provide a valid set name")
|
||||
return
|
||||
end
|
||||
|
||||
if string.find(str, "^Mž") then
|
||||
ImportMacro(str)
|
||||
return
|
||||
end
|
||||
local set = ActionBarSaverDaved.sets[setName] or {}
|
||||
-- if set then
|
||||
-- print(string.format("Set '%s' already exists", setName))
|
||||
-- return
|
||||
-- end
|
||||
|
||||
str = strtrim(str)
|
||||
local data = { strsplit("ž", str) }
|
||||
for _, action in ipairs(data) do
|
||||
local paction = ParseAction(action)
|
||||
if paction then set[paction.slot] = {
|
||||
type = paction.type,
|
||||
id = paction.id,
|
||||
} end
|
||||
end
|
||||
|
||||
ActionBarSaverDaved.sets[setName] = set
|
||||
print(string.format("Imported set '%s'", setName))
|
||||
end
|
||||
|
||||
---@param setName string
|
||||
---@return nil
|
||||
function ImportActionbarSetDialogue(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Must provide a valid set name")
|
||||
return
|
||||
end
|
||||
importingSet = setName
|
||||
importExportFrameTextBox:SetText("")
|
||||
importExportFrame:Show()
|
||||
importExportFrameTextBox:SetFocus()
|
||||
end
|
||||
|
||||
---@return nil
|
||||
function PrintActionbarUsage()
|
||||
print("ABS Slash commands")
|
||||
print("/abs save <set> - Saves your current action bar setup under the given <set>")
|
||||
print("/abs restore <set> - Restores the saved <set>")
|
||||
print("/abs delete <set> - Deletes the saved <set>")
|
||||
print("/abs list - Lists all saved sets")
|
||||
print("/abs alias <spellID> <aliasID> - Adds an alias with <aliasID> to <spellID>")
|
||||
print("/abs unalias <spellID> - Removes all aliases associated with <spellID>")
|
||||
print("/abs aliases - List all spell aliases")
|
||||
print("/abs export <set> - Brings up a dialog to export the given <set>")
|
||||
print("/abs import <set> - Brings up a dialog to import the given <set>")
|
||||
end
|
||||
|
||||
SlashCmdList["ABS"] = function(argv)
|
||||
print("ABS slash", tostring(argv))
|
||||
local args = strsplit(" ", argv)
|
||||
local cmd = args[1]
|
||||
print("ABS slash", tostring(cmd))
|
||||
local args = { strsplit(" ", argv) }
|
||||
local cmd = args[1]
|
||||
|
||||
if cmd == "save" then
|
||||
SaveSet(args[2])
|
||||
end
|
||||
if cmd == "restore" then
|
||||
RestoreSet(args[2])
|
||||
end
|
||||
if cmd == "delete" then
|
||||
DeleteSet(args[2])
|
||||
end
|
||||
if cmd == "list" then
|
||||
ListSets()
|
||||
end
|
||||
if cmd == "alias" then
|
||||
AliasSpell(args[2], args[3])
|
||||
end
|
||||
if cmd == "unalias" then
|
||||
DeleteSpellAliases(args[2])
|
||||
end
|
||||
if cmd == "aliases" then
|
||||
ListAliases()
|
||||
end
|
||||
if cmd == "" or not cmd then
|
||||
PrintUsage()
|
||||
end
|
||||
if cmd == "save" then SaveActionbarSet(args[2]) end
|
||||
if cmd == "restore" then RestoreActionbarSet(args[2]) end
|
||||
if cmd == "delete" then DeleteActionbarSet(args[2]) end
|
||||
if cmd == "list" then ListActionbarSets() end
|
||||
if cmd == "alias" then AliasSpell(args[2], args[3]) end
|
||||
if cmd == "unalias" then DeleteSpellAliases(args[2]) end
|
||||
if cmd == "aliases" then ListAliases() end
|
||||
if cmd == "export" then ExportActionbarSet(args[2]) end
|
||||
if cmd == "import" then ImportActionbarSetDialogue(args[2]) end
|
||||
|
||||
if cmd == "" or not cmd then PrintActionbarUsage() end
|
||||
end
|
||||
SLASH_ABS1 = "/abs"
|
||||
|
42
B64.lua
Normal file
42
B64.lua
Normal file
@@ -0,0 +1,42 @@
|
||||
if not B64 then B64 = {} end
|
||||
local encode, decode = {}, {
|
||||
[strbyte("=")] = false,
|
||||
}
|
||||
for value = 0, 63 do
|
||||
local char = strsub("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", value + 1, value + 1)
|
||||
encode[value] = char
|
||||
decode[strbyte(char)] = value
|
||||
end
|
||||
|
||||
local t = {}
|
||||
function B64.Encode(str)
|
||||
local j = 1
|
||||
for i = 1, strlen(str), 3 do
|
||||
local a, b, c = strbyte(str, i, i + 2)
|
||||
t[j] = encode[bit.rshift(a, 2)]
|
||||
t[j + 1] = encode[bit.band(bit.lshift(a, 4) + bit.rshift(b or 0, 4), 0x3F)]
|
||||
t[j + 2] = b and encode[bit.band(bit.lshift(b, 2) + bit.rshift(c or 0, 6), 0x3F)] or "="
|
||||
t[j + 3] = c and encode[bit.band(c, 0x3F)] or "="
|
||||
j = j + 4
|
||||
end
|
||||
return table.concat(t, "", 1, j - 1)
|
||||
end
|
||||
|
||||
function B64.Decode(str)
|
||||
local j = 1
|
||||
if strlen(str) % 4 ~= 0 then str = str .. string.rep("=", 4 - strlen(str) % 4) end
|
||||
assert(strlen(str) % 4 == 0, format("invalid data length: %d", strlen(str)))
|
||||
for i = 1, strlen(str), 4 do
|
||||
local ba, bb, bc, bd = strbyte(str, i, i + 3)
|
||||
local a, b, c, d = decode[ba], decode[bb], decode[bc], decode[bd]
|
||||
assert(a ~= nil, format("invalid data at position %d: '%s'", i, ba))
|
||||
assert(b ~= nil, format("invalid data at position %d: '%s'", i + 1, bb))
|
||||
assert(c ~= nil, format("invalid data at position %d: '%s'", i + 2, bc))
|
||||
assert(d ~= nil, format("invalid data at position %d: '%s'", i + 3, bd))
|
||||
t[j] = strchar(bit.lshift(a, 2) + bit.rshift(b, 4))
|
||||
t[j + 1] = c and strchar(bit.band(bit.lshift(b, 4) + bit.rshift(c, 2), 0xFF)) or ""
|
||||
t[j + 2] = d and strchar(bit.band(bit.lshift(c, 6) + d, 0xFF)) or ""
|
||||
j = j + 3
|
||||
end
|
||||
return table.concat(t, "", 1, j - 1)
|
||||
end
|
235
KeybindSaver.lua
Normal file
235
KeybindSaver.lua
Normal file
@@ -0,0 +1,235 @@
|
||||
local ADDON_NAME = ...
|
||||
|
||||
-- Initialize saved variables
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("ADDON_LOADED")
|
||||
frame:SetScript("OnEvent", function(self, event, addon)
|
||||
if addon ~= ADDON_NAME then return end
|
||||
|
||||
KeybindSaverDaved = KeybindSaverDaved or {}
|
||||
KeybindSaverDaved.sets = KeybindSaverDaved.sets or {}
|
||||
end)
|
||||
|
||||
---@param setName string
|
||||
---@return nil
|
||||
local function SaveKeybindSet(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
|
||||
---@type table<string, {key1: string, key2: string?}>
|
||||
local set = {}
|
||||
local numBindings = GetNumBindings()
|
||||
|
||||
for i = 1, numBindings do
|
||||
local command, _, key1, key2 = GetBinding(i)
|
||||
if key1 or key2 then set[command] = {
|
||||
key1 = key1,
|
||||
key2 = key2,
|
||||
} end
|
||||
end
|
||||
|
||||
KeybindSaverDaved.sets[setName] = set
|
||||
print(string.format("Saved keybind set '%s'!", setName))
|
||||
end
|
||||
|
||||
---@param setName string
|
||||
---@return nil
|
||||
local function RestoreKeybindSet(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
|
||||
local set = KeybindSaverDaved.sets[setName]
|
||||
if not set then
|
||||
print(string.format("No set with the name '%s' exists", setName))
|
||||
return
|
||||
end
|
||||
|
||||
-- Clear all current bindings first
|
||||
ClearOverrideBindings(frame)
|
||||
|
||||
-- Restore saved bindings
|
||||
for command, keys in pairs(set) do
|
||||
if keys.key1 then SetBinding(keys.key1, command) end
|
||||
if keys.key2 then SetBinding(keys.key2, command) end
|
||||
end
|
||||
|
||||
-- Save the changes
|
||||
SaveBindings(GetCurrentBindingSet())
|
||||
print(string.format("Restored keybind set '%s'", setName))
|
||||
end
|
||||
|
||||
---@param setName string
|
||||
---@return nil
|
||||
local function DeleteKeybindSet(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
|
||||
if not KeybindSaverDaved.sets[setName] then
|
||||
print(string.format("No set with the name '%s' exists", setName))
|
||||
return
|
||||
end
|
||||
|
||||
KeybindSaverDaved.sets[setName] = nil
|
||||
print(string.format("Deleted keybind set '%s'", setName))
|
||||
end
|
||||
|
||||
---@return nil
|
||||
local function ListKeybindSets()
|
||||
local sets = {}
|
||||
for setName in pairs(KeybindSaverDaved.sets) do
|
||||
table.insert(sets, setName)
|
||||
end
|
||||
table.sort(sets)
|
||||
|
||||
if #sets == 0 then
|
||||
print("No keybind sets found")
|
||||
else
|
||||
print("Saved keybind sets:")
|
||||
print(table.concat(sets, ", "))
|
||||
end
|
||||
end
|
||||
|
||||
---@param setName string
|
||||
---@param importStr string
|
||||
---@return nil
|
||||
local function ImportKeybindSet(setName, importStr)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
|
||||
local set = {}
|
||||
local lines = { strsplit("\n", importStr) }
|
||||
|
||||
for _, line in ipairs(lines) do
|
||||
local command, key = strsplit(":", line)
|
||||
if command and key then
|
||||
if not set[command] then set[command] = {} end
|
||||
if not set[command].key1 then
|
||||
set[command].key1 = key
|
||||
else
|
||||
set[command].key2 = key
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
KeybindSaverDaved.sets[setName] = set
|
||||
print(string.format("Imported keybind set '%s'", setName))
|
||||
end
|
||||
|
||||
-- Create the import/export frame
|
||||
local importExportFrame = CreateFrame("Frame", "KBSImportExportFrame", UIParent)
|
||||
importExportFrame:SetSize(512, 512)
|
||||
importExportFrame:SetPoint("CENTER")
|
||||
importExportFrame:SetFrameStrata("HIGH")
|
||||
importExportFrame:EnableMouse(true)
|
||||
importExportFrame:SetMovable(true)
|
||||
importExportFrame:SetResizable(false)
|
||||
importExportFrame:SetBackdrop({
|
||||
bgFile = "Interface/Tooltips/UI-Tooltip-Background",
|
||||
edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
|
||||
tile = true,
|
||||
tileSize = 4,
|
||||
edgeSize = 4,
|
||||
insets = {
|
||||
left = 4,
|
||||
right = 4,
|
||||
top = 4,
|
||||
bottom = 4,
|
||||
},
|
||||
})
|
||||
importExportFrame:SetBackdropColor(0, 0, 0, 0.8)
|
||||
importExportFrame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
|
||||
|
||||
importExportFrame:SetMovable(true)
|
||||
importExportFrame:EnableMouse(true)
|
||||
importExportFrame:RegisterForDrag("LeftButton")
|
||||
importExportFrame:SetScript("OnDragStart", function(self) self:StartMoving() end)
|
||||
importExportFrame:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
|
||||
importExportFrame:SetScript("OnShow", function(self) self:SetScale(1) end)
|
||||
importExportFrame:Hide()
|
||||
|
||||
local importingSet = nil
|
||||
local importExportFrameTextBox = CreateFrame("EditBox", "KBSImportExportFrameTextBox", importExportFrame)
|
||||
importExportFrameTextBox:SetSize(512, 512)
|
||||
importExportFrameTextBox:SetPoint("TOPLEFT", importExportFrame, "TOPLEFT", 0, 0)
|
||||
importExportFrameTextBox:SetFont("Fonts\\FRIZQT__.ttf", 12)
|
||||
importExportFrameTextBox:SetTextColor(1, 1, 1, 1)
|
||||
importExportFrameTextBox:SetTextInsets(20, 20, 20, 20)
|
||||
importExportFrameTextBox:SetMultiLine(true)
|
||||
importExportFrameTextBox:SetAutoFocus(true)
|
||||
importExportFrameTextBox:SetMaxLetters(1000000)
|
||||
importExportFrameTextBox:SetScript("OnEscapePressed", function(self)
|
||||
importExportFrame:Hide()
|
||||
if importingSet then
|
||||
local text = self:GetText()
|
||||
if text and text ~= "" then ImportKeybindSet(importingSet, text) end
|
||||
importingSet = nil
|
||||
end
|
||||
end)
|
||||
|
||||
---@param setName string
|
||||
---@return nil
|
||||
local function ExportKeybindSet(setName)
|
||||
local set = KeybindSaverDaved.sets[setName]
|
||||
if not set then
|
||||
print(string.format("No set with the name '%s' exists", setName))
|
||||
return
|
||||
end
|
||||
|
||||
local export = {}
|
||||
for command, keys in pairs(set) do
|
||||
if keys.key1 then table.insert(export, string.format("%s:%s", command, keys.key1)) end
|
||||
if keys.key2 then table.insert(export, string.format("%s:%s", command, keys.key2)) end
|
||||
end
|
||||
|
||||
local exportStr = table.concat(export, "\n")
|
||||
importExportFrame:Show()
|
||||
importExportFrameTextBox:SetText(exportStr)
|
||||
importExportFrameTextBox:SetFocus()
|
||||
end
|
||||
|
||||
---@param setName string
|
||||
---@return nil
|
||||
local function ImportKeybindSetDialogue(setName)
|
||||
if not setName or setName == "" then
|
||||
print("Set name cannot be empty")
|
||||
return
|
||||
end
|
||||
importingSet = setName
|
||||
importExportFrameTextBox:SetText("")
|
||||
importExportFrame:Show()
|
||||
importExportFrameTextBox:SetFocus()
|
||||
end
|
||||
|
||||
---@return nil
|
||||
local function PrintKeybindUsage()
|
||||
print("Keybind Saver Slash Commands:")
|
||||
print("/kbs save <set> - Saves your current keybinds under the given <set>")
|
||||
print("/kbs restore <set> - Restores the saved <set>")
|
||||
print("/kbs delete <set> - Deletes the saved <set>")
|
||||
print("/kbs list - Lists all saved sets")
|
||||
print("/kbs export <set> - Opens a window to export the given <set>")
|
||||
print("/kbs import <set> - Opens a window to import a keybind set")
|
||||
end
|
||||
|
||||
SLASH_KBS1 = "/kbs"
|
||||
SlashCmdList["KBS"] = function(argv)
|
||||
local args = { strsplit(" ", argv) }
|
||||
local cmd = args[1]
|
||||
|
||||
if cmd == "save" then SaveKeybindSet(args[2]) end
|
||||
if cmd == "restore" then RestoreKeybindSet(args[2]) end
|
||||
if cmd == "delete" then DeleteKeybindSet(args[2]) end
|
||||
if cmd == "list" then ListKeybindSets() end
|
||||
if cmd == "export" then ExportKeybindSet(args[2]) end
|
||||
if cmd == "import" then ImportKeybindSetDialogue(args[2]) end
|
||||
|
||||
if cmd == "" or not cmd then PrintKeybindUsage() end
|
||||
end
|
39
Main.lua
39
Main.lua
@@ -1,32 +1,21 @@
|
||||
local ADDON_NAME, shared = ...
|
||||
local ADDON_NAME = ...
|
||||
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:RegisterEvent("ADDON_LOADED")
|
||||
frame:SetScript("OnEvent", function(self, event, addon)
|
||||
if addon ~= ADDON_NAME then
|
||||
return
|
||||
end
|
||||
if addon ~= ADDON_NAME then return end
|
||||
|
||||
ActionBarSaverReloaded = ActionBarSaverReloaded or {}
|
||||
ActionBarSaverReloaded.spellAliases = ActionBarSaverReloaded.spellAliases or {}
|
||||
ActionBarSaverReloaded.sets = ActionBarSaverReloaded.sets or {}
|
||||
---@class ActionBarSaverDaved
|
||||
---@field spellAliases table<number, number[]>
|
||||
---@field sets table<string, table<number, {type: string, id: number|string}>>
|
||||
ActionBarSaverDaved = ActionBarSaverDaved or {}
|
||||
ActionBarSaverDaved.spellAliases = ActionBarSaverDaved.spellAliases or {}
|
||||
ActionBarSaverDaved.sets = ActionBarSaverDaved.sets or {}
|
||||
|
||||
---@class KeybindSaverDaved
|
||||
---@field sets table<string, table<string, {key1: string, key2: string?}>>
|
||||
KeybindSaverDaved = KeybindSaverDaved or {}
|
||||
KeybindSaverDaved.sets = KeybindSaverDaved.sets or {}
|
||||
end)
|
||||
|
||||
-- function ABS:OnInitialize()
|
||||
-- self.commands = {
|
||||
-- save = self.actions.SaveSet,
|
||||
-- restore = self.actions.RestoreSet,
|
||||
-- delete = self.actions.DeleteSet,
|
||||
-- list = self.actions.ListSets,
|
||||
-- alias = self.actions.AliasSpell,
|
||||
-- unalias = self.actions.DeleteSpellAliases,
|
||||
-- aliases = self.actions.ListAliases,
|
||||
-- }
|
||||
-- end
|
||||
--
|
||||
-- function ABS:HandleCommands(input)
|
||||
-- local cmd, args = Str.split(input, " ", 2)
|
||||
-- local fn = self.commands[Str.toLower(cmd)]
|
||||
--
|
||||
-- if fn then fn(self, args) else self.actions.PrintUsage(self) end
|
||||
-- end
|
||||
-- TODO: Fix equipment sets (saving reloading exporting importing...)
|
1
Meta
Submodule
1
Meta
Submodule
Submodule Meta added at 51a48175fa
25
README.md
25
README.md
@@ -1,16 +1,12 @@
|
||||
# ActionBarSaver:Reloaded
|
||||
# ActionBarSaver:Daved
|
||||
|
||||
## Overview
|
||||
|
||||
ActionBarSaver:Reloaded is an addon for saving and restoring action bar profiles. It is based on the original ActionBarSaver addon but is a full re-write.
|
||||
ActionBarSaver:Daved is an addon for saving and restoring action bar profiles and keybindings. It is based on the original ActionBarSaver addon but is a full re-write.
|
||||
|
||||
All sets are saved by class rather than by character. Additionally, when you list profiles, you will only see profiles that pertain to your class.
|
||||
|
||||
Features such as rename have been deleted for simplicity. To perform a rename, simply save the set with a new name and delete the old set. Additionally, restoring a set will no longer try to re-create macros that do not exist. It will simply notify you of the missing macro and restore nothing for that slot. ABS:R will not work properly if you have multiple macros with the same name, and will warn you of potential issues if you restore a set that has a macro with a shared name.
|
||||
|
||||
A new feature has been added for setting up aliases for spells. A common use case for this would be restoring a single set for two characters that share a class but have a different race. For example, you could create a set on a troll shaman that contains `Berserking` and then add an alias for `War Stomp` using `/abs alias 20554 20549`. If you do this, when you restore a set it will first try to restore the proper spell but will also try each alias that you set up. A spell can have as many aliases as you want.
|
||||
|
||||
## Usage
|
||||
## Action Bar Saver Usage
|
||||
|
||||
`/abs save <set>` - Saves your current action bar setup under the given <set>\
|
||||
`/abs restore <set>` - Restores the saved <set>\
|
||||
@@ -18,7 +14,20 @@ A new feature has been added for setting up aliases for spells. A common use cas
|
||||
`/abs list` - Lists all saved sets\
|
||||
`/abs alias <spellID> <aliasID>` - Adds an alias with <aliasID> to <spellID>\
|
||||
`/abs unalias <spellID>` - Removes all aliases associated with <spellID>\
|
||||
`/abs aliases` - List all spell aliases
|
||||
`/abs aliases` - List all spell aliases\
|
||||
`/abs export <set>` - Opens a window to export the given <set>\
|
||||
`/abs import <set>` - Opens a window to import an action bar set
|
||||
|
||||
## Keybind Saver Usage
|
||||
|
||||
The addon also includes a keybind saver that allows you to save and restore your keybindings. This is useful for maintaining different keybind setups for different specs or situations.
|
||||
|
||||
`/kbs save <set>` - Saves your current keybinds under the given <set>\
|
||||
`/kbs restore <set>` - Restores the saved <set>\
|
||||
`/kbs delete <set>` - Deletes the saved <set>\
|
||||
`/kbs list` - Lists all saved sets\
|
||||
`/kbs export <set>` - Opens a window to export the given <set>\
|
||||
`/kbs import <set>` - Opens a window to import a keybind set
|
||||
|
||||
## Known Issues
|
||||
|
||||
|
@@ -1,31 +0,0 @@
|
||||
## 1.0.7 (2024-06-30)
|
||||
|
||||
- Updated for Cata classic
|
||||
|
||||
## 1.0.6 (2023-08-29)
|
||||
|
||||
- TOC bump for ICC patch
|
||||
|
||||
## 1.0.5 (2023-06-20)
|
||||
|
||||
- TOC bump for ToGC patch
|
||||
|
||||
## 1.0.4 (2023-01-18)
|
||||
|
||||
- TOC bump for WOTLK patch
|
||||
|
||||
## 1.0.3 (2022-11-09)
|
||||
|
||||
- Fixed bug with equipment sets not being restored properly
|
||||
|
||||
## 1.0.2 (2022-10-27)
|
||||
|
||||
- Fixed bug where totem sets were not being saved or restored
|
||||
|
||||
## 1.0.1 (2022-09-26)
|
||||
|
||||
- Fixed bug related to restoring sets containing companions and mounts
|
||||
|
||||
## 1.0.0 (2022-07-15)
|
||||
|
||||
- Initial re-write of the addon
|
5
deploy.sh
Normal file
5
deploy.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
mkdir ABS
|
||||
cp -r *.lua ABS
|
||||
cp -r *.toc ABS
|
||||
7z a ABS.zip ABS
|
||||
rm -rf ABS
|
57
release.sh
Normal file
57
release.sh
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Figuring out the tag..."
|
||||
TAG=$(git describe --tags --exact-match 2>/dev/null || echo "")
|
||||
if [ -z "$TAG" ]; then
|
||||
# Get the latest tag
|
||||
LATEST_TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
|
||||
# Increment the patch version
|
||||
IFS='.' read -r -a VERSION_PARTS <<< "$LATEST_TAG"
|
||||
VERSION_PARTS[2]=$((VERSION_PARTS[2]+1))
|
||||
TAG="${VERSION_PARTS[0]}.${VERSION_PARTS[1]}.${VERSION_PARTS[2]}"
|
||||
# Create a new tag
|
||||
git tag $TAG
|
||||
fi
|
||||
echo "Tag: $TAG"
|
||||
|
||||
echo "Building the thing..."
|
||||
sed -i "s/## Version: .*/## Version: $TAG/" ActionBarSaverDaved.toc
|
||||
git add ActionBarSaverDaved.toc ActionBarSaverDaved.lua
|
||||
git commit -m "Release $TAG"
|
||||
git tag -f $TAG
|
||||
git push origin $TAG
|
||||
|
||||
rm ActionBarSaverDaved-${TAG}.zip
|
||||
mkdir ActionBarSaverDaved
|
||||
cp *.lua *.toc ActionBarSaverDaved
|
||||
7z a ActionBarSaverDaved-${TAG}.zip ActionBarSaverDaved
|
||||
rm -rf ActionBarSaverDaved
|
||||
|
||||
echo "Creating a release..."
|
||||
TOKEN="$GITEA_API_KEY"
|
||||
GITEA="https://git.site.quack-lab.dev"
|
||||
REPO="dave/wow_ABS"
|
||||
# Create a release
|
||||
RELEASE_RESPONSE=$(curl -s -X POST \
|
||||
-H "Authorization: token $TOKEN" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"tag_name": "'"$TAG"'",
|
||||
"name": "'"$TAG"'",
|
||||
"draft": false,
|
||||
"prerelease": false
|
||||
}' \
|
||||
$GITEA/api/v1/repos/$REPO/releases)
|
||||
|
||||
# Extract the release ID
|
||||
echo $RELEASE_RESPONSE
|
||||
RELEASE_ID=$(echo $RELEASE_RESPONSE | awk -F'"id":' '{print $2+0; exit}')
|
||||
echo "Release ID: $RELEASE_ID"
|
||||
|
||||
echo "Uploading the things..."
|
||||
curl -X POST \
|
||||
-H "Authorization: token $TOKEN" \
|
||||
-F "attachment=@ActionBarSaverDaved-${TAG}.zip" \
|
||||
"$GITEA/api/v1/repos/$REPO/releases/${RELEASE_ID}/assets?name=ActionBarSaverDaved-${TAG}.zip"
|
||||
rm ActionBarSaverDaved-${TAG}.zip
|
12
stylua.toml
Symbolic link
12
stylua.toml
Symbolic link
@@ -0,0 +1,12 @@
|
||||
syntax = "All" # Specify a disambiguation for the style of Lua syntax being formatted. Possible options: All (default), Lua51, Lua52, Lua53, Lua54, LuaJIT, Luau, CfxLua
|
||||
column_width = 120 # Approximate line length for printing. Used as a guide for line wrapping - this is not a hard requirement: lines may fall under or over the limit.
|
||||
line_endings = "Windows" # Line endings type. Possible options: Unix (LF) or Windows (CRLF)
|
||||
indent_type = "Tabs" # Indent type. Possible options: Tabs or Spaces
|
||||
indent_width = 4 # Character size of single indentation. If indent_type is set to Tabs, this option is used as a heuristic to determine column width only.
|
||||
quote_style = "AutoPreferDouble" # Quote style for string literals. Possible options: AutoPreferDouble, AutoPreferSingle, ForceDouble, ForceSingle. AutoPrefer styles will prefer the specified quote style, but fall back to the alternative if it has fewer string escapes. Force styles always use the specified style regardless of escapes.
|
||||
call_parentheses = "Always" # Whether parentheses should be applied on function calls with a single string/table argument. Possible options: Always, NoSingleString, NoSingleTable, None, Input. Always applies parentheses in all cases. NoSingleString omits parentheses on calls with a single string argument. Similarly, NoSingleTable omits parentheses on calls with a single table argument. None omits parentheses in both cases. Note: parentheses are still kept in situations where removal can lead to obscurity (e.g. foo "bar".setup -> foo("bar").setup, since the index is on the call result, not the string). Input removes all automation and preserves parentheses only if they were present in input code: consistency is not enforced.
|
||||
space_after_function_names = "Never" # Specify whether to add a space between the function name and parentheses. Possible options: Never, Definitions, Calls, or Always
|
||||
collapse_simple_statement = "Always" # Specify whether to collapse simple statements. Possible options: Never, FunctionOnly, ConditionalOnly, or Always
|
||||
|
||||
[sort_requires]
|
||||
enabled = false
|
Reference in New Issue
Block a user