QoL: premade group filter panel for the Group Finder - #1138
Open
nulltyto wants to merge 1 commit into
Open
Conversation
nulltyto
marked this pull request as ready for review
August 2, 2026 01:49
nulltyto
marked this pull request as draft
August 2, 2026 01:58
nulltyto
force-pushed
the
feat/premade-group-filter
branch
from
August 2, 2026 03:26
15e5b72 to
e9299ca
Compare
nulltyto
marked this pull request as ready for review
August 2, 2026 03:31
nulltyto
marked this pull request as draft
August 2, 2026 03:35
nulltyto
force-pushed
the
feat/premade-group-filter
branch
from
August 2, 2026 22:30
e9299ca to
45853a9
Compare
Adds a Filters panel beside the Premade Groups browser that narrows a Dungeon search to the groups you actually want, plus result-row display options and the Group Finder conveniences gathered onto one options page. Filters panel (attached to the Group Finder, since these change per search): minimum leader score, needs a tank, needs a healer, my role available, fits my whole party, difficulty, a dungeon whitelist of icon cells with All / None, a raid whitelist, and an optional user-written filter expression (score > 2800 and tanks == 0). Options page (Quality of Life -> Group Finder): master enable, dim delisted / declined groups, the expression toggle, leader score on entries, group member display (spec icons / spec icons + class bar), quick signup, persistent signup note, auto insert keystone and instance reset announce. The four that already existed move here unchanged, same DB keys and behaviour. Groups are removed from the list only through Blizzard's own advanced filter (C_LFGList.SaveAdvancedFilter, applied server-side by the search), never by rewriting the panel's results array -- that array is read back into Blizzard's own sign-up and rebuild paths, and writing it permanently taints the Group Finder for the session. That covers leader score, the role needs, the four dungeon difficulties and the dungeon whitelist. Blizzard's filter is dungeons-only and has no field for the rest, so delisted, declined, party fit, the expression and all raid criteria are applied as a read-only verdict that dims the row instead. Reading results taints nothing. The verdict pass stands down entirely while the group data is protected, since a secret value throws on comparison. Changing any filter re-runs the search immediately: the controls are SecureActionButtonTemplate buttons forwarding to the search panel's own refresh button, so the search runs in Blizzard's execution rather than ours. That makes them protected frames, so the panel's layout and wiring defer to PLAYER_REGEN_ENABLED when they are hit in combat. The score box is typed rather than clicked and carries its own Apply button. Forwarding is gated to the dungeon browse. LFGListSearchPanel_DoSearch discards the advanced filter for every other category, so a forwarded search on Raids or Legacy Raids could not act on the change that triggered it and would only spend a search against the server throttle. On those tabs the clickbutton attribute is cleared; the control's own work and the dimming pass still run, only the search is suppressed. There are no sort controls: reordering means writing the results array, with the same consequence. Blizzard's comparator already sorts declined groups last and friends first. Nothing is hooked, framed or registered until the feature is enabled. Verified in content on 12.0.7 with group data protected.
nulltyto
force-pushed
the
feat/premade-group-filter
branch
from
August 2, 2026 22:40
45853a9 to
1360b46
Compare
Contributor
Author
|
Note as of 2026-08-02 15:44 the dungeon filter functionality has been relatively sorted. Currently, the raid sortability as provided by blizzard is sub-par; which is limited our ability to filter without taint. Will continue looking into approaches for the raid filtering. |
nulltyto
marked this pull request as ready for review
August 3, 2026 01:39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Adds a Filters panel beside Blizzard's Premade Groups browser that narrows a
search to the groups you actually want, plus two result-row display tweaks and a
new Group Finder page in the Quality of Life options. Every setting defaults
off, and nothing is hooked, framed or registered until the feature is first
enabled.
Filters panel (attached to
LFGListFrame.SearchPanel, because these changeper search rather than per session):
whole party.
Mythic for raids.
short names used elsewhere in the suite), and a raid whitelist. Both start
collapsed showing only All / None; open them for per-instance picking. A
whitelist filters by what it has in common with the list the current tab
enumerates, so selections on Raids and Legacy Raids do not leak into each
other and stale season entries simply go inert.
(
score > 2800 and tanks == 0).Row display (two independent settings, usable without the filter panel):
role icons so nothing is clipped.
Blizzard's leaver-penalty badge is mirrored onto the overlay so it stays
visible.
Settings consolidation: the four Group Finder settings that lived on the QoL
page (Auto Insert Keystone, Announce Instance Reset, Quick Signup, Persistent
Signup Note) move to the new page unchanged — same DB keys, same behaviour — so
everything Group Finder related is in one place.
Taint posture
This is the part I would most like scrutinised, and it is the reason the
implementation looks the way it does.
Groups are only ever removed through Blizzard's own advanced filter. The
panel builds a filter table and hands it to
C_LFGList.SaveAdvancedFilter; thesearch applies it server-side. That is a C call — nothing we pass becomes Lua
state Blizzard reads back, and the results arrive through Blizzard's own
untainted event path. This covers minimum leader score, the role needs, the four
dungeon difficulties and the dungeon whitelist.
An earlier revision of this PR filtered by rewriting
panel.results, and thatwas wrong. Blizzard reads that array back into the elements it builds, so every
button.resultIDis tainted; clicking a row carries the taint intoLFGListSearchPanel_SelectResultand thenLFGListApplicationDialog_Show, whichwrites
LFGListApplicationDialog.activityID— a field Blizzard reads before itwrites, so it can never be written securely again for the session. From that
point Blizzard's own result-list rebuild sorts tainted, and its comparator
compares
numBNetFriends, which is a secret value inside an instance. Onesign-up from a filtered list was enough to produce pure-Blizzard error stacks
with this addon named. Three fields behave this way
(
LFGListFrame.activePanel,ApplicationDialog.activityID,SearchPanel.previousSearchText); none of them can be repaired short of/reload. Probing, pausing and re-arming were all tried and all are too late.The ownership seam is gone, and with it that entire class of bug.
What Blizzard's filter cannot express is dimmed rather than removed. It is
dungeons-only (
LFGListSearchPanel_DoSearchnils the advanced filter for everyother category) and has no field for delisted, declined, party fit, the
expression box or any raid criterion. Those are applied as a read-only
verdict that shades the row. Reading results taints nothing; only writing does.
Filter changes re-run the search immediately. A saved advanced filter
normally only takes effect on the next search, and we cannot start one —
C_LFGList.Searchis flaggedHasRestrictions, andLFGListSearchPanel_DoSearchwrites Blizzard state on our execution. So thepanel's click controls are
SecureActionButtonTemplatebuttons forwarding toSearchPanel.RefreshButton: Blizzard'sSECURE_ACTIONS.clickruns the search inits own context, not ours. The consequence is that these are protected frames, so
the panel's layout and attribute wiring defer to
PLAYER_REGEN_ENABLEDwhen theyare hit in combat. The score box is typed rather than clicked, so it carries its
own Apply button.
Forwarding is gated to the dungeon browse, because only a dungeon search can
act on what these controls save (see below). On the other tabs the
clickbuttonattribute is cleared, which
SECURE_ACTIONS.clickhandles by doing nothing — ittests
delegate and not delegate:IsForbidden()before clicking.PreClickstillfires, so the control's own work and the dimming pass still run; only the
pointless search is suppressed.
There are no sort controls. Reordering the browse means writing the results
array or its elements, which is the same poison by another route. Blizzard's own
comparator already sorts declined groups last and friends first.
Known limitation: raid criteria can only dim, not remove
Raid and Legacy Raid criteria (the raid whitelist and raid difficulty) shade
non-matching rows rather than removing them, and as far as I can establish there
is currently no way to do better. Every server-side lever is closed:
LFGListSearchPanel_DoSearchsetsadvancedFilters = nilfor any category other thanGROUP_FINDER_CATEGORY_ID_DUNGEONS, so re-running the search on a raid tabapplies no filter at all. Blizzard's own UI agrees:
FilterButton:SetupMenuonly builds the advanced filter menu for dungeons, and the non-dungeon branch
offers language options alone.
C_LFGList.Searchis calledwith
nilin the text slot — the box is only used for the auto-createcomparison. And the editbox is declared
securityDisableSetText="true"with asecureReferenceKey, so it cannot be written to regardless.panel.filters/panel.preferredFiltersare off limits. They areBlizzard frame fields read back on every search; writing them is the ownership
seam described above. They are also category-coarse — they are what the Raids
vs Legacy Raids tabs themselves set.
So this is a Blizzard-side limitation rather than a design choice, and the panel
is explicit about it: the raid whitelist tooltip says non-matching raid groups
are shaded rather than removed. If a raid-capable filter API appears, the raid
criteria can move across to it without touching anything else — they are already
expressed the same way as the dungeon ones.
Remaining rules, all held to throughout:
LFGListSearchPanel_DoSearch,C_LFGList.Search,LFGListSearchPanel_UpdateResults,LFGListSearchPanel_UpdateResultListorLFGListSearchEntry_Update.file-locals; anything keyed by a Blizzard row lives in an external weak-keyed
table.
pcall'd accessor and every consumedfield is
issecretvalue()-checked. A failed or secret read makes the criterionpass (fail-open), and if anything comes back secret the verdict pass stands
down entirely — reading a secret is safe, but comparing one throws.
HookScript, neverSetScript, on Blizzard frames.SetPointis replaced onRaiderIO's own anchor frame so its profile window stops landing on top of the
panel. That frame is third-party and non-secure; the same move on a Blizzard
frame would be a taint bug.
setfenv'd table holding nothingbut sanitised scalars and four math helpers — no
_G, noC_LFGList, no wayback out. Every failure mode keeps the result.
While the panel is enabled it is the authority for the nine advanced-filter
fields it owns; the other seven are merged through untouched. The user's own
pre-takeover filter is snapshotted the first time the feature is enabled and
restored when it is switched off, so this is not a one-way door into a rewritten
dropdown.
Testing
C_ChatInfo.InChatMessagingLockdown()true and 27 of 29GetSearchResultInfofields secret, which is the state that used to detonate.An
issecurevariable()sweep over the LFG frame fields, the LFGList globalsand the data provider's
resultIDs came back clean on every one. Taint issticky until
/reload, so a clean sweep after a session of filtering andsigning up is a real result rather than a lucky sample.
exercised on dungeon, raid and legacy-raid tabs.