File Details
cepgp_lootmaster-8.7.2.zip
- R
- Jun 1, 2026
- 847.63 KB
- 612
- 2.5.5
- Classic TBC
File Name
cepgp_lootmaster-8.7.2.zip
Supported Versions
- 2.5.5
Changes
8.7.2 — 2026-05-22 → 2026-06-01
Features
Raid Groups — Duplicate Members Fixed + Visual Class-Coloured Grid
- Reported bug: Adding a member like "akathriel" then later "Akathriel" (or "Otuken" vs "Ötüken") created TWO entries in the same group — table keys were case- and diacritic-sensitive and
AddPlayerToRaidGrouponly stripped the realm before storing. The same person could end up in the group N times. - Fix: new
LootMaster:CanonicalizeMemberName(name)helper:- Strips realm suffix and trims whitespace.
- Looks up the name in the guild cache case-insensitively and, if found, returns the exact form the WoW server stores (so "akathriel" → "Akathriel", "otuken" → "Ötüken" with the correct diacritics).
- Falls back to reusing the casing of an already-existing raid-group member with the same lower-cased form.
- Otherwise ASCII title-cases the first byte (leaves multi-byte diacritic-leading names untouched).
- Both
AddPlayerToRaidGroupandRemovePlayerFromRaidGroupnow canonicalise first, plus a defensive case-insensitive dedup loop inAddPlayerToRaidGroupmakes a duplicate insertion impossible even if canonicalisation misses a corner case.CreateRaidGroupalso became case-insensitive for group names ("ASYA" and "asya" can no longer coexist). - Display upgrade — proper popup: AceConfig forces each inline description cell to ~20 % of the panel width, which truncates names to 4 letters (
Asa…,Avi…,Co…). So the inline grid was scrapped in favour of a standalone WoW frame opened by a new "Show Members" button next to the group selector. The popup is a real raid-roster grid: 5 columns × however-many-rows it needs, each cell ~155 px wide, with the class icon (32×32 fromInterface\WORLDSTATEFRAME\Icons-Classes) on the left and the full class-coloured name on the right. Hover any cell to see class / level / rank in a tooltip. The popup is draggable, ESC-closable, and auto-sizes to the member count. The inline header line now also shows a small class-count summary (e.g.5 paladin · 4 priest · 3 mage…) coloured per class so you can scan composition without opening the popup. - Where:
lootmaster_core.lua(CanonicalizeMemberName, updatedCreateRaidGroup/AddPlayerToRaidGroup/RemovePlayerFromRaidGroup);lootmaster_player_ui.lua(newLootMaster:ShowRaidGroupMembersFrame(groupName)+ helper locals_RG_GetOrCreateFrame/_RG_GetOrCreateCell);cepgp_lootmaster_ml/lootmaster_options.lua(rgMembersHeadernow shows class-count summary; newrgMembersShowbutton replaces the broken inline grid).
Auto-EP — Visible Reasons When It Doesn't Fire + ML-Check Retry
- Reported by another guild: "Randomly the addon is not giving the EP even though auto-give EP is selected." With no feedback in chat, the ML had no way to diagnose what was different about those kills.
- Root cause: every "skip" path in
LootMaster:AutoAwardBossEPusedself:Debug(...)— debug-only output that doesn't show in chat unless debug mode is on. So a kill could silently abort for half a dozen reasons (not the ML, profile setting off, per-boss disabled, EP value 0, etc.) and the ML would just see nothing. - Additional cause we found while there: at the moment
ENCOUNTER_ENDfires, the loot-method state can briefly be unset / transitional, causingIsPlayerMasterLooter()to return false even when the player IS the ML. The function then aborted with no retry — guaranteed to look "random". - Fix:
- Every skip path is now
self:Print(...)with a clear coloured reason. The ML sees exactly why EP wasn't awarded for a given boss ("you are not the Master Looter","the global Auto-Award EP toggle is OFF","this specific boss is disabled","configured EP is 0","raidEPSettings missing from profile", etc.). - The ML check now retries once after a 2-second delay if it initially returns false — covers the transient
ENCOUNTER_ENDflicker. GuildRoster()is called once right before the bulk award, refreshing the cached guild roster so officer-note writes don't fail silently for stale/missing roster entries (a known cause of partial misses on raid-wide bulk EP).
- Every skip path is now
- Where:
lootmaster_core.luaLootMaster:AutoAwardBossEP(bossName, _attempt).
Roll Tracker — Broadcasts Stop Once Item Is Awarded
- Reported by another guild: After the ML awarded an item to someone, the roll tracker on other clients sometimes lingered or kept getting updated for the decided item — late-arriving responses from candidates (someone changing their mind, or a delayed click) still triggered
ROLLUPDATEbroadcasts even though the loot was already in someone's bag. - Two-part fix:
GiveLootToCandidate(cepgp_lootmaster_ml/lootmaster_ml.lua) now setsloot.awarded = trueafterGiveMasterLootruns, cancels any in-flight 1-secondSendRollTrackerUpdatethrottle for the same item, and broadcasts a newLOOTAWARDEDcommand with the item link so every client knows the item is done.SendRollTrackerUpdateand_DoSendRollTrackerUpdateboth bail early whenloot.awardedis set, so subsequent candidate responses can never produce a ghost update for an awarded item.- Player-side (
cepgp_lootmaster/lootmaster_player.lua) handlesLOOTAWARDED: removes the item from the roll display immediately (not after the existing 5-second LOOTED-cleanup delay) and drops any queued late-arriving ROLLUPDATEs.
Roll Tracker — Close Button Actually Closes Now
- Reported by another guild: The roll tracker (the "Roll Sonuclari" frame that pops up on the right showing who needed/passed/rolled what) kept reopening every time a new response arrived, even after the player had explicitly clicked its X button. Made the close button useless during loot announcements.
- Root cause in
lootmaster_player_ui.luaUpdateRollDisplay():frame:Show()was called unconditionally on EVERY incomingROLLUPDATEbroadcast from the ML. So a closed frame got re-shown as soon as any candidate changed their response. - Fix: The close button now sets
frame._userClosed = true.UpdateRollDisplay()respects that flag on subsequent updates and skipsframe:Show()— UNLESS a genuinely new item arrives (isNewItem == true), in which case the flag is cleared and the frame reopens (new content is worth surfacing). The flag is also cleared onClearRollDisplay()and on the safety auto-hide timer, so a fresh announcement cycle always starts clean. - Effect: Close → stays closed for the current item. Next item arriving → pops back up. Same-item updates → silently update in the background.
AceDB Profile Is Now Guild-Scoped (not character-scoped)
- Before: The shared AceDB profile that every character was forced onto was named
"Fhe - Thunderstrike"— a character/realm name. Conceptually weird (the data belonged to a guild, not a character) and it broke if Fhe ever transferred or got renamed. - Now: The profile is named after the GUILD (
"A N A D O L U"for the ANADOLU guild). Every character in the same guild automatically shares one profile — sessions, audit log, raid groups, EP settings, button presets, root admins, the lot. Characters apply to the guild, not the other way around. - One-time migration (
MigrateProfileToGuildScope): on next login, the addon detects the guild name (from liveGetGuildInfoor the persisteddb.global.guildCache.guildName), copies the legacy"Fhe - Thunderstrike"profile into<GuildName>, deletes the old profile, re-pointsprofileKeysfor every character to the new name, and setsdb.global.profileV3GuildScoped = true. Prints a green "Profile renamed to guild scope" chat line. Idempotent — only runs once. - Chicken-and-egg handling: At addon
OnEnabletimeGetGuildInfocan be nil for 2-3 seconds. We try the guild-scoped name first, then fall back to the legacy name so existing data still loads. As soon asRefreshGuildCachesucceeds and reveals the guild name, the migration kicks in and switches the profile. - Where:
lootmaster_core.lua— newGetGuildScopedProfileName()helper, newMigrateProfileToGuildScope(targetName), updated V2 migration block andRefreshGuildCacheto call them. - Effect on data: Nothing is lost.
Fhebecomes just "a character in ANADOLU with admin rights" instead of "the magic profile name everyone shares". Hardcoded root admin status forFhe(inROOT_ADMIN_CHARACTERS) is unaffected; the auto-recorded GM is unaffected.
Zombie Guild-Store Keys — Source Fixed + Existing Cleaned
- Found:
CEPGPLootMasterGuild(the per-guild data store for raid groups, alts, EP settings, etc.) had 5 zombie top-level keys alongside the legitimate"A N A D O L U"entry —"Fhe - Thunderstrike","Kurtadam","Fhe","Akathriel","Akathriel - Thunderstrike". Total: 518 lines (~16 KB) of duplicate guild data that never should have existed. - Root cause:
LootMaster:GetSessionStoreKey()had a player-name fallback for the case whereGetGuildInfo("player")returned nil. On login that API takes 2-3 seconds to populate after the addon's OnEnable fires — so the addon would write under the player name (a zombie key) during that early window, then write under the real guild name once guild info loaded. The zombie keys piled up across sessions because nothing ever cleaned them up. - Fix in code:
GetSessionStoreKey()now returns nil (not the player name) when the guild isn't available. Every Load/Save store function (LoadSessionsFromStore,SaveSessionsToStore,LoadAuditLogFromStore,SaveAuditLogToStore,LoadGuildDataFromStore,SaveGuildDataToStore) returns early on nil.RefreshGuildCache(which fires onGUILD_ROSTER_UPDATE) now re-runs all three loads once the guild name resolves, so the early bail is invisible to users — sessions / audit / guild-data all load slightly later instead of being missed. - Fix on disk: The 5 zombie blocks were surgically deleted from
WTF/Account/<acct>/SavedVariables/cepgp_lootmaster.lua(with a timestamped.bakbackup). File shrank from 27,053 lines → 26,535 lines.
Profile Storage Consolidation — One Area, Account-Wide Sharing Preserved
- Changed: The addon used to keep "saved profile snapshots" (the data behind
/lm cfg save//lm cfg loadand the Save Profile / Load Profile From UI controls) in a separate top-level table atCEPGPLootMaster.global.characterProfiles. The live data lived inCEPGPLootMaster.profiles[<profileName>](the AceDB profile). The two could drift — most painfully whenraidGroupsended up only in a snapshot and the active profile lost it. - Now: Snapshots live INSIDE the active profile at
db.profile.savedSnapshots[<charName>]. Since every character is forced onto the sharedFhe - ThunderstrikeAceDB profile, the snapshots are still account-wide (every alt sees the same snapshot list). There is no second top-level area anymore. - Save/Load feature unchanged in behaviour:
/lm cfg save | load | list | delete | info, the Save/Load Profile UI controls, and the snapshot list all keep working — they just point at the new location. - Direct file cleanup (because the game was closed at the time): the legacy
["characterProfiles"]block was surgically removed fromWTF/Account/<acct>/SavedVariables/cepgp_lootmaster.luadirectly (947 lines, with a timestamped.bakwritten alongside). No runtime migration was needed. - Removed:
MigrateCharacterProfilesToSnapshots(), the OnEnable call that invoked it, the olderRecoverFromCharacterProfileSnapshots(verbose)function, and the/lm migrateslash command — all were diagnostic scaffolding while the bug was being chased. The codebase no longer referencesdb.global.characterProfilesanywhere (the lingering nil-assignment inside the V2 migration block is left in place as harmless legacy cleanup for users who haven't run V2 yet). - Fixed:
/lm cfg listwas still reading fromdb.global.characterProfiles[charName]to fetch each snapshot's timestamp — now reads fromEnsureSavedSnapshots()directly. - API surface for ML options panel: New
LootMaster:EnsureSavedSnapshots()helper returns thedb.profile.savedSnapshotstable (lazy-init). The ML AceConfig UI uses this instead of touchingdb.global.characterProfilesdirectly. - Where:
lootmaster_core.lua(Save/Load/Get/Delete/Info functions, migration, OnEnable hook);cepgp_lootmaster_ml/lootmaster_options.lua(Account Profile UI section).
lm-sync Web Admin — One Canonical Settings View (no more per-character clones)
- Changed: The admin "Synced Settings" panel used to render one
profile_<character>card per character that had ever synced (profile_Fhe,profile_Akathriel, etc.) — all displaying the same data in raw JSON. Now there is exactly one canonical settings row per guild (primary_profile), derived from the most authoritative character available:Fhe→ first recorded root admin → first non-empty profile. The character it came from is shown as a smallsource: <Name>tag on the card. - New structured panel:
primary_profilerenders as cards grouped by area (Loot Buttons, EPGP, Auto Looter) instead of a JSON blob. Each loot button shows its name, short label, and GP value; EPGP shows decay percent, auto-decay enabled, last-decay date, always-on flag, and attendance start week; Auto Looter shows the BoE/BoU threshold, enabled flag, and default candidate. - EPGP Config card renders the
epgp_configrow as a two-column key/value grid. - JSON is opt-in: A "Show JSON" toggle in the section header pops a raw-JSON view of every setting row; "Export JSON" downloads the full settings blob as
lm-sync-settings-<guild>.json. - Backend:
extract_settings()inserver/luaparser.pynow picks ONE canonical profile (ranking: short nameFhe→ recorded root admin → SHARED_PROFILE name → first profile) and emits exactly oneprimary_profilesetting row containing_source_characterplus the synced keys./sync/upload-rawnow purges legacyprofile_*rows for the guild on every upload — so existing per-character clones in the DB go away on the next sync. - One-off cleanup for installations with already-stale
profile_*rows that never get re-synced:docker exec lootmaster_sync_db psql -U lmsync -d lmsync -c "DELETE FROM settings WHERE setting_key LIKE 'profile_%';"
Raid Groups — Config Panel UI + Bulk Add by Guild Rank
- New panel: ML Settings → LootMaster Admin → Raid Groups. Root admins can create groups, select an existing group, see its current members (class-coloured), add/remove individual members, and delete the group. The previously orphaned core API (
CreateRaidGroup,AddPlayerToRaidGroup,DeleteRaidGroup, etc.) finally has a front-end. - Bulk add by guild rank: Within the selected group, root admins now get a rank dropdown + checkbox list of every guild member at that rank. Currently-in-group members are pre-checked and decorated with a green ✓; unchecking + Apply removes them; checking + Apply adds them. Mirrors the rank-based bulk-select pattern from the legacy session admin panel.
- Bulk add from current raid: A one-click "Add All Current Raid Members" button adds every player in your current WoW raid group to the selected raid group. Useful for snapshotting a fresh team.
- Filter pill in attendance view: The "All Raid Groups" pill on the Loot History → Attendance dashboard filters sessions to those a group "belongs to" (≥ half the group's members attended). The pill no longer overlaps the search bar — search is now anchored to the rightmost pill (
pillGroup:RIGHT) instead ofpillFrom:RIGHT.
lm-sync Web Admin — Raid Groups Section
- New section on the guild detail page (
c:/Projects/lm-sync/admin/src/App.jsx): a card grid showing every raid group and its members, rendered above the Synced Settings block. Members display as pill chips with realm stripped. - Backend:
luaparser.pygainsextract_raid_groups()(de-duplicates across profiles) andextract_root_admins()(readsdb.global.rootAdminNames). The/sync/upload-rawendpoint now persists both as singleton setting rows (setting_key="raid_groups"andsetting_key="root_admins"), so the existing/admin/guilds/{id}payload carries them with no schema change. - i18n: New keys
raidGroups,membersadded to both English and Turkish dictionaries.
Localisation Sweep — Loot Add/Edit Dialog
- All previously hardcoded English strings in the Add/Edit Loot dialog (
"Charged %d GP to %s for %s","Failed to charge GP...","Reversed %d GP...","Edit reversal...","Manual add: %s","Manual","Free", the announce-to-raid templates, and the"Search players..."placeholder) are now wrapped inL[]with Turkish translations. The audit-log strings ("Added: %s ...","Edited: %s ...") are deliberately kept in English so they remain greppable for ops.
Hardcoded Root Admin List Reduced to "Fhe" Only
- Changed:
ROOT_ADMIN_CHARACTERSinlootmaster_core.luais now a single-entry table containing onlyFhe. The previous hardcoded list (Akathriel,Fhe,Majihu,Avianthus) has been removed. - Why: Hardcoded admin lists are unfair to other guilds using this addon. The only character we need pinned for guarantee is
Fhe(the primary developer / config source). The current Guild Master is auto-recorded as a root admin at runtime byRecordGuildMasterAsRootAdmin()(introduced in 8.7.2) and persisted intodb.global.rootAdminNames— so the GM always has root access for free, on any guild, without needing a hardcoded entry. Any additional root admins are added by the GM/Fhe via/lm rootadmin add <player>or the Root Admins config panel. - Cleanup: Removed the unused
IsPlayerAkathriel()helper fromcepgp_lootmaster_ml/lootmaster_options.lua(it was defined but never referenced). Removed a stale "Start from existing Akathriel profile" comment in the V2 migration block. Test/dryrun mock-candidate fake names (Avianthus,Akathriel) are kept as harmless test fixtures — they do not grant permissions.
Permission System Overhaul — Tier-Based Matrix + Root Admin Management UI
- New centralised gate: Every UI button and comm handler now resolves authorisation through
LootMaster:Can(action, ctx)instead of mixing inlineIsRootAdmin / IsPlayerMasterLooter / IsSessionAdminchecks. The default policy is stored as tier strings inPERMISSION_DEFAULTS(lootmaster_core.lua), and root admins can override any action's tier via the in-game Permission Matrix. - Tiers:
root(root admins only),ml_or_root(master looters and root admins),all(everyone),off(disabled). - Split edit/delete gates in loot history: The
[E](edit) action button now appears for MLs and root admins (loot.edit_entry=ml_or_root); the[X](delete) action button is now root-admin only (loot.delete_entry=root). Previously both flowed through a single "session admin" gate. - Session admins removed: The legacy session-admin tier (gold "permanent" admins, green temporary admins,
/lm xJ7qsecret command) is gone. Only root admins can delete sessions or loot entries. Master Looters still start, continue, and end sessions and award loot exactly as before — only destructive operations now require root. - Multi-root-admin support: The Guild Master is auto-recorded as a root admin (introduced in 8.7.2), but additional root admins can be added via
/lm rootadmin add <player>or the new Root Admins config panel (see below). No secret command needed.
Root Admins + Permission Matrix Config Panel
- Location: ML Settings → LootMaster Admin tab → Root Admins subgroup and Permission Matrix subgroup.
- Root Admins panel: Shows the current list of root admins (gold). For root admins, adds an "Add Root Admin" input and a "Remove Root Admin" dropdown. Hardcoded ROOT_ADMIN_CHARACTERS are immutable; recorded admins (
db.global.rootAdminNames) can be added/removed. - Permission Matrix panel (root-admin only): For every action in
PERMISSION_DEFAULTS, root admins can pick a tier from a dropdown (Root / ML+Root / All / Off). Overrides are stored indb.global.permissionOverrides[action]. A "Reset to Defaults" button clears all overrides. - Why: The old "Session Administration" panel (with permanent-vs-temporary admin terminology and rank-based bulk-add) was confusing and exposed too many ways to hand out elevated access. The new panel makes the policy explicit and lets each root admin tune the local gates on their own machine.
Slash command
/lm rootadmin(alias/lm ra) —[list | add <player> | remove <player>]. The old hidden/lm xJ7qcommand is removed.
Raid Composition Builder — Player Picker Hides Sub-68 Characters
- When assigning a player to a spec slot, the picker listed every guild member of the matching class regardless of level, so low-level alts and bank characters cluttered the list. Members below level 68 are now filtered out. Members with an unknown level (a brief mid-roster-load state) are still shown so nobody is lost to a stale cache.
- Applied to BOTH composition builders: the embedded module (
cepgp_lootmaster/Libs/RaidGroups/lrg_ui.lua) and the standalone Raid Tools addon (cepgp_lootmaster_rt/rt_ui.lua).
Raid Groups Module — Trimmed to the Essentials
- The embedded raid-composition planner under
Libs/RaidGroups/(ported from the RT addon) carried a lot of machinery the core addon doesn't need. Removed: composition cloning (the copy button +Comp:Clone); the multi-active-composition view (_activeComps,AddActiveComp/RemoveActiveComp, the "+ Comp" picker, theisMultirender branch); all sharing/sync UI (Sync with All, Sync with…, the owner padlock/lock, theRT_SYNC_PLAYERpopup — sharing was already a no-op stub); every audit hook (theRT.audit:Recordcall sites, theHideAuditPanel/UpdateFooterStatusno-op stubs, and the audit/controller/inspect/options/minimap/sharing stub block inlrg_init.lua); and a 305-line deadComp:GetCompositionOptionsTableAceConfig table that nothing referenced. - Kept (by design): single-composition editing, rename, bench rows, Invite All, the rank filter, and the buff/debuff coverage panel.
- Net size:
lrg_ui.lua77 KB → 60 KB,lrg_compositions.lua22 KB → 9 KB.
Attunement Check — Account-Wide Aware + Persistent Cache + Selective Guild Polling
- Reported: Players who completed an attunement on their MAIN are auto-attuned on alts (account-wide), but
/lm attshowed those alts as NOT attuned — the check only read the alt character's own quest flags, which aren't set for an account-wide auto-attunement. - Key constraint: there is no API to query another player's quest/item state remotely — each client can only self-report (which is why the check whispers everyone). The account-wide quest API
C_QuestLog.IsQuestFlaggedCompletedOnAccountdoes not exist on this Anniversary client (confirmednil), so a purely client-side fix isn't possible.GetLocalAttuneStatusstill probes for it at runtime and uses it when present, for forward-compatibility. - Fix — alt→main aggregation via the existing officer-note alt links: attune status is cached per MAIN character (
db.global.attuneCache, upgrade-only since TBC attunement is permanent). A character counts as attuned for a raid when its main is. New helpersGetEffectiveAttune,CacheAttuneStatus,_AttuneMainKey,IsAttuneFullyCached. The response handler and the initiator's own row both cache and display the effective (own OR main-cached) status;AddAttuneCheckMemberbackfills from cache so auto-attuned alts show green immediately. - Selective Guild polling: the Guild button no longer broadcasts to the whole guild every run. Every online member is still listed (backfilled from cache), but a live request goes only to members whose main is NOT already cached as fully attuned. Confirmed-attuned members are shown from cache and never re-polled (permanent); the not-yet-attuned are re-polled each run so progress is caught. The first check populates the cache; later checks shrink to just the people still missing attunements.
- Where:
Libs/RosterChecks/rosterchecks.lua;lootmaster_player_ui.lua(AddAttuneCheckMember, the Guild/Raid button handlers).
Guild Master Auto-Recorded as Root Admin (Multi-Guild Support)
- New: On every guild roster refresh, the current Guild Master's character name is recorded into a persisted list and granted root-admin access — name-based, not via a live "is GM" check at every call site. This lets the addon work cleanly for guilds outside A N A D O L U: any guild's GM automatically becomes a root admin without needing the hardcoded
ROOT_ADMIN_CHARACTERStable to be edited. - How: New
LootMaster:RecordGuildMasterAsRootAdmin()inlootmaster_core.luaiteratesself.GuildCache.memberslooking forrankIndex == 0and writes the GM's short name intodb.global.rootAdminNames. Called at the tail end ofRefreshGuildCache(after the cache becomes valid + afterPersistGuildCacheToDisk). Additive and idempotent — safe to call on every roster update. - Where the name is consulted:
IsRootAdminnow also matches againstdb.global.rootAdminNames(plain case-insensitive name match) in addition to the existing hardcoded list and the liverankIndex == 0cache check. Because the list is persisted, root-admin status survives/reloadand is in effect on subsequent logins even before the live roster has loaded for the session. - Also:
GetSessionAdminsFromConfignow includes the recorded GM names, so they appear in admin enumerations alongsideROOT_ADMIN_CHARACTERSandTEMP_SESSION_ADMINS. - Storage:
db.global.rootAdminNamesis a{shortName = true}table; lazy-initialised on first record. The existing liverankIndex == 0fallback inIsRootAdminis intentionally retained as a safety net.
UI Improvements
Raid Session History — Wider Frame for Long Instance Names
- Changed: The Loot History dashboard (
LootMasterHistoryFrame) is now 1180px wide (was 1000), and each of the four dashboard cards (Instance / Status / Master Looter / Items) is 230px wide (was 190). Long instance names such as "Coilfang: Serpentshrine Cavern" now fit comfortably inside the Instance card. - Why the in-between width: An initial bump to 255px caused the cards to overlap the Attendance tab button (anchored top-right of the frame). The 230px / 1180px combination keeps the cards, search bar and Attendance button visually clear of each other.
- Where:
lootmaster_player_ui.lua—frame:SetWidth(1180)in the history frame creator;card:SetSize(230, HIST_CARD_HEIGHT)in the localCreateHistCardhelper. Layout is otherwise unchanged.
Bug Fixes
Add / Edit Loot Entry dialog now accepts shift-click from anywhere
- Fixed: Shift-clicking an item link in chat, bags, the character pane, inspect, AH, mail, or any other Blizzard UI surface now populates the item slot in the Add Loot Entry and Edit Loot Entry dialogs. Previously the dialog only listened to
ChatEdit_InsertLink, which fires only when a chat edit box happens to be open — so shift-clicking a bag item with no chat box up did nothing. We now also hookHandleModifiedItemClick, Blizzard's universal modified-click chokepoint, so the dialog captures the link regardless of where the click originates. - Also: The item slot now supports right-click to clear the selected item (previously you had to close the dialog to change your mind). Left-click still picks up a cursor-held item; drag-and-drop still works.
- Where:
lootmaster_player_ui.lua— new_AdminLootDialog_AcceptLinkhelper,hooksecurefunc("HandleModifiedItemClick", ...),itemBtn:RegisterForClicks("LeftButtonUp", "RightButtonUp")and the right-button branch in the OnClick handler.
Missing locale entry crash: "All Raid Groups"
- Fixed: AceLocale strict mode threw
Missing entry for 'All Raid Groups'when opening the Loot History → Attendance view because the new raid-group filter pill (added in the 8.7.2 raid-groups feature) was looking up a locale key that had not been added tolocale\enUS.lua/locale\trTR.lua. - Where: Added
L["All Raid Groups"],L["Raid Groups"],L["Root Admins"],L["Permission Matrix"],L["Add Root Admin"],L["Remove Root Admin"](plus several long description strings used by the new Root Admins / Permission Matrix panels) to both locale files.
Loot History — 2× of the Same Item to the Same Player Now Records Both
- Reported: When a boss dropped two of the same item and both went to one player, only one entry appeared in the loot history.
- Two causes: (1) a proximity de-dup in
RecordLootHistoryEntrydropped any matching item/player/GP/distributor seen within 2 seconds — regardless of award id — collapsing two genuine awards into one; (2) award ids were built fromtime()(1-second resolution), so two awards in the same second that fell back to anitemLink-based id collided and the second was dropped by theseenAwardIdsgate. - Fix: the proximity de-dup now runs only when there is no award id (its intended fallback role for chat-scraped loot); when an award id is present the
seenAwardIdsgate is authoritative, so two distinct ids both record. Award ids are built by a newLootMaster:MakeAwardId(base)helper that appends a per-login monotonic counter, guaranteeing uniqueness even within the same second. All seven generation sites switched to it (cepgp_lootmaster_ml/lootmaster_ml.lua×4,lootmaster_lootframe.lua, the manual-entry path inlootmaster_player_ui.lua, and theauto:placeholder inLibs/TradeWatch/tradewatch.lua— theauto:/manual:prefixes are preserved so the placeholder-removal logic still matches^auto:). - Where:
Libs/SessionSync/sessionsync.lua(RecordLootHistoryEntry),lootmaster_core.lua(MakeAwardId), plus the seven call sites.
Loot History — Sort Crash on Numeric Columns (base out of range)
- Fixed: Sorting the loot-history table by a
numstrcolumn (e.g. GP) could throwbad argument #2 to 'tonumber' (base out of range).string.gsubreturns two values (the cleaned string AND a replacement count); as the last argument totonumber(...)that count was passed as the numeric base, which errors whenever it lands outside 2–36. Parenthesising thegsubtruncates it to one value. Latent bug — it surfaced now because the loot-history de-dup fix above lets a genuine second row exist, which the comparator then evaluated. - Where:
lootmaster_player_ui.luaSortHistoryData.
Internal
- New core API surface:
LootMaster.PERMISSION_DEFAULTS,LootMaster.PERMISSION_TIERS,LootMaster:GetPermissionTier(action),LootMaster:SetPermissionTier(action, tier),LootMaster:ResetPermissionOverrides(),LootMaster:GetPermissionActions(),LootMaster:ListRootAdmins()(now returns a sorted list),LootMaster:PrintRootAdmins()(chat output, slash-command use). Can()evaluates the tier resolved from overrides → defaults. Unknown actions and unknown tiers both returnfalse.- The old
admin_membersAceConfig group incepgp_lootmaster_ml/lootmaster_options.luais renamed tolegacy_admin_membersand hidden — the args (rank-based bulk add, manual add/remove, permanent-vs-temporary distinction) remain in-tree for one release as a safety net before removal.
Core File Split Into 10 Libs/ Subsystem Modules
lootmaster_core.luawent from 11,405 → ~5,800 lines. Ten self-contained subsystems were extracted into their own folders, loaded from the TOC immediately after the core file (they only attach methods to theLootMastertable, so the only ordering requirement is "after core"):Libs/Permissions/permissions.lua— root admins,Can(), permission tiers, session admins.Libs/RaidTeams/raidteams.lua— guild-team grouping +NormalizeRaidName.Libs/AdminAudit/adminaudit.lua— admin-action log + comm audit request/response + the raw-comm / chat-audit listeners.Libs/Guild/guild.lua— guild cache, alt linking, EP/GP-by-rank.Libs/InstanceTracking/instancetracking.lua— zone/instance segments, combat-log boss detection, auto-EP.Libs/TradeWatch/tradewatch.lua— trade-window loot watch + chat-loot scrape +GetRaidWeekStart.Libs/ImportExport/importexport.lua— JSON/CSV/encoded session I/O + dialogs + session summary.Libs/SessionSync/sessionsync.lua— comm broadcasts, chunked transfer, the centralCommandReceiveddispatcher, root-admin session browser.Libs/RosterChecks/rosterchecks.lua— version + attunement checks.Libs/Minimap/minimap.lua— LDB icon + right-click menu.
- File-local upvalues that crossed the new module boundaries were lifted onto the
LootMastertable:TEMP_SESSION_ADMINS→LootMaster._sessionAdminsRuntime;GetShortName→LootMaster._GetShortName; andCOMM_PREFIX_MAP/SEND_PREFIX/iVersion/version/debugare now exposed asLootMaster.*fields (snapshotted at module load inrosterchecks.lua). - Load-order fixes (the subtle part of the split): the broadcast-log hooks that wrap
SendSyncCommand/CommandReceived— plus theLootMaster._CoreCommandReceivedsnapshot thatlootmaster_player.luafalls through to — were moved from the end oflootmaster_core.luato the end ofLibs/SessionSync/sessionsync.lua, because those two methods are now defined there and load after core (the original hooks capturednil, throwingattempt to call upvalue 'origCommandReceived'). TheInitRawCommListener/InitChatAuditListenerstartup calls likewise moved to the end ofLibs/AdminAudit/adminaudit.lua.
Configuration Changes
Minimap Menu Permission Panel Removed; Visibility Now Fixed in Code
- Removed from UI: The configurable "Minimap Menu" group under ML Settings → Tools → Minimap Permissions — the per-item Guild Members / Admins / Specific Rank toggles and rank dropdowns — has been hidden from the AceConfig panel. The dead config-table args remain in
cepgp_lootmaster_ml/lootmaster_options.lua(the group hashidden = true) rather than being excised, to avoid risking a brace-mismatch that would break the entire config window. - Why: The previous configurable system added complexity for little gain and was reported as not behaving consistently. A small, predictable set of fixed rules is simpler and easier to reason about.
- New fixed behaviour (hardcoded in
LootMaster:HasMinimapMenuPermission,lootmaster_core.lua):- Show EPGP Ranks — visible to everyone.
- Show EPGP History — visible to everyone.
- Mini Session Bar — visible only to the Master Looter and Root Admins.
- One chokepoint, both menus:
HasMinimapMenuPermissionis called from both the core'sShowMinimapMenuand the Raid Tools module'sRT:ShowExtendedMinimapMenu(cepgp_lootmaster_rt/rt_core.lua). Changing the function once propagates to both — no per-call-site edits. - Implementation note:
HasMinimapMenuPermissionshort-circuits at the top with ado ... endblock returning the new fixed visibility; the legacy permission-table evaluation code below remains intentionally unreachable (kept in place for safety / reference). - Migration: No SavedVariables migration required.
db.profile.minimapMenuPermissionsanddb.profile.minimapMenuRankscontinue to exist in the DB but are no longer consulted at runtime.

