From b9bb16f632d11f2196b27decb13c43b4de11719b Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Fri, 29 May 2026 10:43:54 +0200 Subject: [PATCH 1/5] fix(MultiCast): nil-safe Enum.ClassMask guard so file-load can't crash for custom classes --- Bartender4/MultiCastBar.lua | 13 ++++++++----- Bartender4/Options/MultiCastBar.lua | 9 ++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Bartender4/MultiCastBar.lua b/Bartender4/MultiCastBar.lua index fc138b2..db25865 100644 --- a/Bartender4/MultiCastBar.lua +++ b/Bartender4/MultiCastBar.lua @@ -7,11 +7,14 @@ if not HasMultiCastActionBar then return end local classMask = UnitClassMask("player") --- CoA: the SHAMAN/HERO mask check doesn't know about CoA custom classes --- (e.g. Witchdoctor, which also uses the totem bar). Fall back to the --- game-created MultiCastActionBarFrame: if the engine produced it for this --- player, we wrap it regardless of class. -if not bit.contains(EnumUtil.CombineMasks(Enum.ClassMask.SHAMAN, Enum.ClassMask.HERO), classMask) +-- CoA: Enum.ClassMask only knows vanilla classes (SHAMAN/HERO); custom classes +-- (e.g. Witchdoctor) won't match. EnumUtil/Enum.ClassMask may also be nil on +-- this client. Guard both: if the mask API is unavailable OR the player's class +-- isn't in the vanilla set, fall through to the MultiCastActionBarFrame check — +-- if the engine created the bar for this player we wrap it regardless of class. +local _vanillaMask = EnumUtil and Enum and Enum.ClassMask + and EnumUtil.CombineMasks(Enum.ClassMask.SHAMAN, Enum.ClassMask.HERO) +if _vanillaMask and not bit.contains(_vanillaMask, classMask) and not MultiCastActionBarFrame then return end diff --git a/Bartender4/Options/MultiCastBar.lua b/Bartender4/Options/MultiCastBar.lua index 889a184..c968116 100644 --- a/Bartender4/Options/MultiCastBar.lua +++ b/Bartender4/Options/MultiCastBar.lua @@ -7,9 +7,12 @@ if not HasMultiCastActionBar then return end local classMask = UnitClassMask("player") --- CoA: see MultiCastBar.lua — same gate, same fallback so the options --- panel is registered for custom classes (e.g. Witchdoctor) too. -if not bit.contains(EnumUtil.CombineMasks(Enum.ClassMask.SHAMAN, Enum.ClassMask.HERO), classMask) +-- CoA: see MultiCastBar.lua — same gate, same fallback so the options panel is +-- registered for custom classes (e.g. Witchdoctor) too. Guard EnumUtil / +-- Enum.ClassMask for nil in case they are absent on this client. +local _vanillaMask = EnumUtil and Enum and Enum.ClassMask + and EnumUtil.CombineMasks(Enum.ClassMask.SHAMAN, Enum.ClassMask.HERO) +if _vanillaMask and not bit.contains(_vanillaMask, classMask) and not MultiCastActionBarFrame then return end From c88e53d18b9d56ce90cf632c85f66294c092b7b5 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Fri, 29 May 2026 20:23:32 +0200 Subject: [PATCH 2/5] fix(libs): pcall AceGUI OnGamePadButtonDown (3.3.5 has no gamepad script type) --- Bartender4/libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Bartender4/libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua b/Bartender4/libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua index ee5a83b..07c8f76 100644 --- a/Bartender4/libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua +++ b/Bartender4/libs/AceGUI-3.0/widgets/AceGUIWidget-Keybinding.lua @@ -199,7 +199,7 @@ local function Constructor() button:SetScript("OnKeyDown", Keybinding_OnKeyDown) button:SetScript("OnMouseDown", Keybinding_OnMouseDown) button:SetScript("OnMouseWheel", Keybinding_OnMouseWheel) - button:SetScript("OnGamePadButtonDown", Keybinding_OnKeyDown) + pcall(button.SetScript, button, "OnGamePadButtonDown", Keybinding_OnKeyDown) button:SetPoint("BOTTOMLEFT") button:SetPoint("BOTTOMRIGHT") button:SetHeight(24) From bb20d1df36adc95b276d07c4ab15dd1b38eee44d Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Fri, 29 May 2026 20:51:21 +0200 Subject: [PATCH 3/5] ci(release): hide auto-generated source archives (hide_archive_links) --- .gitea/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 709a7cd..1b1b66b 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -37,7 +37,7 @@ jobs: RID=$(curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \ -H "Content-Type: application/json" \ "$API/repos/$REPO/releases" \ - -d "$(jq -nc --arg t "$TAG" '{tag_name:$t,name:$t,draft:false,prerelease:false}')" \ + -d "$(jq -nc --arg t "$TAG" '{tag_name:$t,name:$t,draft:false,prerelease:false,hide_archive_links:true}')" \ | jq -r '.id') fi echo "release id: $RID" From 6c0c1f06243c008e2b55a265876269179384f74d Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Wed, 10 Jun 2026 02:11:46 +0200 Subject: [PATCH 4/5] ci(release): sync release.yml from coa-template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hide_archive_links is only honored by Gitea on release edit, not create — add the PATCH step after create/lookup so auto-generated source archive links actually stay hidden (coa-template 90874c5). --- .gitea/workflows/release.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 1b1b66b..2f93975 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -41,6 +41,10 @@ jobs: | jq -r '.id') fi echo "release id: $RID" + # Gitea honors hide_archive_links only on edit, not create — PATCH it + # so the auto-generated Source Code (zip/tar.gz) links stay hidden. + curl -sf -X PATCH -H "Authorization: token $GITEA_TOKEN" -H "Content-Type: application/json" \ + "$API/repos/$REPO/releases/$RID" -d '{"hide_archive_links":true}' >/dev/null || true # Upload every dist/*.zip. Per-asset failures don't fail the job — # we want partial releases to still publish rather than block the # whole pipeline on one big file. From aadeb06793702946ce01d8b06847476d4c9492d2 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Wed, 10 Jun 2026 02:14:21 +0200 Subject: [PATCH 5/5] fix: cache form signature only after bar refresh actually runs UPDATE_SHAPESHIFT_FORMS firing before the ActionBars module exists cached the signature without refreshing, causing the identical later event to be skipped. --- Bartender4/CoAAuraConditionals.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Bartender4/CoAAuraConditionals.lua b/Bartender4/CoAAuraConditionals.lua index a6fec89..a227103 100644 --- a/Bartender4/CoAAuraConditionals.lua +++ b/Bartender4/CoAAuraConditionals.lua @@ -129,11 +129,13 @@ refresh:SetScript("OnEvent", function(self, event) -- UPDATE_SHAPESHIFT_FORMS spam. local sig = currentFormSignature() if sig == lastFormSignature then return end - lastFormSignature = sig 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 + -- Only cache the signature once a refresh actually ran, so an event + -- arriving before module init doesn't swallow the next identical one. + lastFormSignature = sig end)