feat(paging): accept [aura:Name] / [form:Name] / [stance:Name] form-name conditionals
Translate non-numeric stance/form/aura conditionals to [stance:N] via
GetShapeshiftFormInfo() before handing the string to RegisterStateDriver.
Lets CoA custom-class users write self-documenting paging strings:
[aura:Beetle Form]6;1 -- instead of [stance:1]6;1
[stance:Beetle Form/Wasp Form]9
[noaura:Beetle Form]2
All three keywords (aura, form, stance) are accepted equivalently when
the value is a non-numeric form name. Numeric values pass through
unchanged. Unresolved names are left as-is so the failure is visible
at parse time.
Re-applies on UPDATE_SHAPESHIFT_FORMS / PLAYER_ENTERING_WORLD so newly
learned forms take effect without a /reload (defers during combat
lockdown to avoid taint).
Bumps Version to 4.4.2-2-g3b02ee4-coa1 so the loaded copy is
identifiable in-game.
This commit is contained in:
+5
-2
@@ -5,9 +5,9 @@
|
|||||||
## X-Curse-Repository-ID: wow/bartender4/mainline
|
## X-Curse-Repository-ID: wow/bartender4/mainline
|
||||||
|
|
||||||
## Title: Bartender4
|
## Title: Bartender4
|
||||||
## Notes: Simple and Advanced combined - Bartender4 ActionBar AddOn
|
## Notes: Simple and Advanced combined - Bartender4 ActionBar AddOn (CoA fork: [aura:Name] / [form:Name] paging)
|
||||||
|
|
||||||
## Version: 4.4.2-2-g3b02ee4
|
## Version: 4.4.2-2-g3b02ee4-coa1
|
||||||
|
|
||||||
## Author: Nevcairiel
|
## Author: Nevcairiel
|
||||||
## X-Email: h.leppkes at gmail dot com
|
## X-Email: h.leppkes at gmail dot com
|
||||||
@@ -55,6 +55,9 @@ ButtonBar.lua
|
|||||||
StateBar.lua
|
StateBar.lua
|
||||||
ActionBar.lua
|
ActionBar.lua
|
||||||
|
|
||||||
|
## CoA patches ##
|
||||||
|
CoAAuraConditionals.lua
|
||||||
|
|
||||||
## Buttons ##
|
## Buttons ##
|
||||||
ActionButton.lua
|
ActionButton.lua
|
||||||
PetButton.lua
|
PetButton.lua
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
--[[
|
||||||
|
CoA Bartender4 patch — translate [aura:Name] / [form:Name] /
|
||||||
|
non-numeric [stance:Name] in paging conditionals into [stance:N].
|
||||||
|
|
||||||
|
Why: Blizzard's secure macro parser (SecureCmdOptionParse) only
|
||||||
|
accepts a numeric index for [stance:] / [form:] and has no [aura:]
|
||||||
|
keyword at all. Addons cannot register new conditionals into the
|
||||||
|
secure parser. So the only honest place to do this is *before* we
|
||||||
|
hand the string to RegisterStateDriver — we resolve form names to
|
||||||
|
indices via GetShapeshiftFormInfo() and rewrite the keyword.
|
||||||
|
|
||||||
|
Scope: only shapeshift forms are resolvable this way. That covers
|
||||||
|
Druid, Warrior stances, Death Knight presences, Priest Shadowform,
|
||||||
|
and every CoA custom-class form (Venomancer, Wildkin, etc.) since
|
||||||
|
those all live in the shapeshift bar. Non-form auras (regular
|
||||||
|
buffs) cannot be expressed as a stance index and would need a
|
||||||
|
synthetic state-driver attribute — out of scope here.
|
||||||
|
|
||||||
|
Usage in Bartender4 paging:
|
||||||
|
[aura:Beetle Form]6;1 -- equivalent to [stance:1]6;1 (if Beetle Form is form 1)
|
||||||
|
[form:Beetle Form]6;1
|
||||||
|
[stance:Beetle Form]6;1
|
||||||
|
[stance:Beetle Form/Wasp Form]6;1 -- slash-list works too
|
||||||
|
[noaura:Beetle Form]2
|
||||||
|
|
||||||
|
All three keywords (aura, form, stance) are accepted equivalently
|
||||||
|
when the value is a non-numeric form name. Numeric values pass
|
||||||
|
through unchanged. Unresolvable names are left as-is so the failure
|
||||||
|
is visible at conditional-parse time rather than silently swallowed.
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Bartender4 = _G.Bartender4
|
||||||
|
if not Bartender4 then return end
|
||||||
|
|
||||||
|
local KEYWORDS = { "nostance", "noform", "noaura", "stance", "form", "aura" }
|
||||||
|
local KEYWORD_OUT = {
|
||||||
|
stance = "stance", form = "stance", aura = "stance",
|
||||||
|
nostance = "nostance", noform = "nostance", noaura = "nostance",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function shapeshiftIndexByName(name)
|
||||||
|
if type(GetNumShapeshiftForms) ~= "function" or type(GetShapeshiftFormInfo) ~= "function" then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local n = GetNumShapeshiftForms() or 0
|
||||||
|
local lname = name:lower()
|
||||||
|
for i = 1, n do
|
||||||
|
local _, fname = GetShapeshiftFormInfo(i)
|
||||||
|
if fname and fname:lower() == lname then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function translateValueList(values)
|
||||||
|
local parts, anyTranslated = {}, false
|
||||||
|
for v in values:gmatch("[^/]+") do
|
||||||
|
local trimmed = v:match("^%s*(.-)%s*$") or v
|
||||||
|
if trimmed:match("^%d+$") or trimmed == "" then
|
||||||
|
parts[#parts + 1] = trimmed
|
||||||
|
else
|
||||||
|
local idx = shapeshiftIndexByName(trimmed)
|
||||||
|
if idx then
|
||||||
|
parts[#parts + 1] = tostring(idx)
|
||||||
|
anyTranslated = true
|
||||||
|
else
|
||||||
|
parts[#parts + 1] = trimmed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(parts, "/"), anyTranslated
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bartender4:CoATranslateConditionals(s)
|
||||||
|
if type(s) ~= "string" or s == "" then return s end
|
||||||
|
for _, kw in ipairs(KEYWORDS) do
|
||||||
|
local outKw = KEYWORD_OUT[kw]
|
||||||
|
s = s:gsub(kw .. ":([^,%]]+)", function(value)
|
||||||
|
local newValue, didTranslate = translateValueList(value)
|
||||||
|
if didTranslate then
|
||||||
|
return outKw .. ":" .. newValue
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Re-apply paging when shapeshift form set changes (new form learned,
|
||||||
|
-- spec respec, etc.) so freshly-resolvable names take effect without
|
||||||
|
-- a /reload. Skipped during combat lockdown — RegisterStateDriver is
|
||||||
|
-- secure and the SetAttribute calls inside UpdateStates would taint.
|
||||||
|
local refresh = CreateFrame("Frame")
|
||||||
|
refresh:RegisterEvent("UPDATE_SHAPESHIFT_FORMS")
|
||||||
|
refresh:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
|
refresh:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||||
|
local pendingRefresh = false
|
||||||
|
refresh:SetScript("OnEvent", function(self, event)
|
||||||
|
if InCombatLockdown and InCombatLockdown() then
|
||||||
|
pendingRefresh = true
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if event == "PLAYER_REGEN_ENABLED" and not pendingRefresh then return end
|
||||||
|
pendingRefresh = false
|
||||||
|
local mod = Bartender4 and Bartender4.GetModule and Bartender4:GetModule("ActionBars", true)
|
||||||
|
if not mod or not mod.actionbars then return end
|
||||||
|
for _, bar in pairs(mod.actionbars) do
|
||||||
|
if bar and bar.UpdateStates then bar:UpdateStates() end
|
||||||
|
end
|
||||||
|
end)
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
CoA Bartender4
|
||||||
|
==============
|
||||||
|
|
||||||
|
This is the Children of Ascension fork of [Bartender4][upstream] by
|
||||||
|
Hendrik "Nevcairiel" Leppkes, vendored from Ascension's WotLK 3.3.5
|
||||||
|
client (`/srv/add01/wow-ascension/Interface/AddOns/Bartender4`,
|
||||||
|
upstream version `4.4.2-2-g3b02ee4`).
|
||||||
|
|
||||||
|
[upstream]: https://github.com/Nevcairiel/Bartender4
|
||||||
|
|
||||||
|
What we patched
|
||||||
|
---------------
|
||||||
|
|
||||||
|
A single feature: paging conditionals can refer to **shapeshift forms
|
||||||
|
by name**, not just by numeric stance index.
|
||||||
|
|
||||||
|
```
|
||||||
|
[aura:Beetle Form]6;1 -- equivalent to [stance:N]6;1
|
||||||
|
[form:Beetle Form]6;1
|
||||||
|
[stance:Beetle Form]6;1 -- non-numeric value also accepted
|
||||||
|
|
||||||
|
[stance:Beetle Form/Wasp Form]9 -- slash-lists work
|
||||||
|
[noaura:Beetle Form]2 -- negation works
|
||||||
|
```
|
||||||
|
|
||||||
|
Three keywords are accepted equivalently when the value is a non-numeric
|
||||||
|
form name: `aura:`, `form:`, `stance:` (and their `no…:` negations).
|
||||||
|
All resolve via `GetShapeshiftFormInfo()` and get rewritten to
|
||||||
|
`[stance:N]` before the string reaches Blizzard's secure macro parser.
|
||||||
|
|
||||||
|
This covers every Venomancer / Wildkin / etc. CoA custom-class form,
|
||||||
|
plus stock Druid / Warrior / DK / Priest forms — anything that lives
|
||||||
|
in the shapeshift bar. Non-form auras (regular buffs) cannot be
|
||||||
|
expressed as a stance index and are out of scope.
|
||||||
|
|
||||||
|
Why upstream can't accept this patch as-is
|
||||||
|
------------------------------------------
|
||||||
|
|
||||||
|
`SecureCmdOptionParse` is hardcoded in the WoW client; addons cannot
|
||||||
|
register new conditional keywords into it. Our translation pass runs
|
||||||
|
*before* `RegisterStateDriver`, rewriting `[aura:Name]` to `[stance:N]`
|
||||||
|
at addon scope. That works on a private server with predictable form
|
||||||
|
sets, but upstream serves multiple expansions and clients where the
|
||||||
|
keyword `aura` may eventually mean something different (or be reserved
|
||||||
|
by Blizzard) — so it stays a fork patch.
|
||||||
|
|
||||||
|
Files we touched
|
||||||
|
----------------
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|---|---|
|
||||||
|
| `Bartender4.toc` | Version `…-coa1`, loads `CoAAuraConditionals.lua`, Notes appended |
|
||||||
|
| `StateBar.lua` | 3-line guard before `RegisterStateDriver` calls our translator |
|
||||||
|
| `CoAAuraConditionals.lua` | New file — the translator + `UPDATE_SHAPESHIFT_FORMS` re-apply |
|
||||||
|
| `.gitattributes` | `* -text` so we don't normalise upstream CRLF (keeps merges clean) |
|
||||||
|
|
||||||
|
Pulling future upstream releases
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Upstream lives at <https://github.com/Nevcairiel/Bartender4>. The patch
|
||||||
|
is small and the touched files are stable, so future merges should be
|
||||||
|
mostly painless:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git remote add upstream https://github.com/Nevcairiel/Bartender4.git
|
||||||
|
git fetch upstream
|
||||||
|
git merge upstream/master # or whatever upstream's default is
|
||||||
|
# resolve trivial conflicts in StateBar.lua + Bartender4.toc
|
||||||
|
luac -p StateBar.lua CoAAuraConditionals.lua
|
||||||
|
```
|
||||||
|
|
||||||
|
Deploying
|
||||||
|
---------
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rsync -a --delete \
|
||||||
|
--exclude=.git --exclude=.gitattributes --exclude='README-CoA.md' \
|
||||||
|
/home/sub/repos/coa/coa-bartender/ \
|
||||||
|
/srv/add01/wow-ascension/Interface/AddOns/Bartender4/
|
||||||
|
```
|
||||||
|
|
||||||
|
Same for `wow-ptr`. After deploy the in-game version string reads
|
||||||
|
`4.4.2-2-g3b02ee4-coa1`, so you can confirm the patched copy is loaded.
|
||||||
|
|
||||||
|
Verifying it works
|
||||||
|
------------------
|
||||||
|
|
||||||
|
In-game, run any of:
|
||||||
|
|
||||||
|
```
|
||||||
|
/run print(SecureCmdOptionParse("[stance:Beetle Form]yes;no"))
|
||||||
|
/run print(SecureCmdOptionParse("[aura:Beetle Form]yes;no"))
|
||||||
|
```
|
||||||
|
|
||||||
|
Both should print **`no`** even when in Beetle Form, because Blizzard's
|
||||||
|
parser still doesn't understand the names — but Bartender4's paging
|
||||||
|
**will** work, because the translator rewrites the string before
|
||||||
|
handing it to the state driver. To verify *that*, set up paging as
|
||||||
|
`[aura:Beetle Form]6;1` in Bar 1 → State Configuration → Custom, shift
|
||||||
|
into Beetle Form, and watch Bar 1 swap to page 6.
|
||||||
@@ -187,6 +187,10 @@ function StateBar:UpdateStates(returnOnly)
|
|||||||
UnregisterStateDriver(self, "page")
|
UnregisterStateDriver(self, "page")
|
||||||
self:SetAttribute("state-page", "0")
|
self:SetAttribute("state-page", "0")
|
||||||
|
|
||||||
|
-- CoA: rewrite [aura:Name] / [form:Name] / [stance:Name] -> [stance:N]
|
||||||
|
if Bartender4.CoATranslateConditionals then
|
||||||
|
statedriver = Bartender4:CoATranslateConditionals(statedriver)
|
||||||
|
end
|
||||||
RegisterStateDriver(self, "page", statedriver or "0")
|
RegisterStateDriver(self, "page", statedriver or "0")
|
||||||
|
|
||||||
self:SetAttribute("_onstate-assist-help", [[
|
self:SetAttribute("_onstate-assist-help", [[
|
||||||
|
|||||||
Reference in New Issue
Block a user