v1.2.0
What's new
VoidstormPartyLedger
v1.2.0 (2026-10-06)
- feat: run timeline, pre-key group check, and expanded public API
Timeline builds an ordered event list per encounter (joins, leaves, boss
kills, completion). GroupCheck prints a summary of the current group against
the ledger when a keystone starts. The public API gains GetEncounter,
GetEncounters with filters, GetRatingHistory, GetTimeline, GetLastSeenRating,
GetWeeklyDigest, GetPlayerTags, GetCurrentSeason, SetFavorite and SetAvoid, and
registers as the PartyLedger module with the Voidstorm core so VoidstormKeys
can read runs and people from it. - fix: UI review pass — dialogs, pooled rows, timers, filters, relation markers
StaticPopup edit-box dialogs accept on Enter again (11.2 renamed the child
frames; shared accessors walk to the dialog). Dropdown overlays close with
their owner, history rows are pooled, timers use NewTimer and are cancelled on
hide, deletes refresh the list, season filter and By Dungeon view, timeline
rows in the browser, relation markers (guild/friend/BNet), rating popup skips
known players when configured, colour text helpers in SharedUI. - fix: 12.0 API audit — combat stats, encounter outcomes, comm, realm handling
Combat stats: COMBAT_LOG_EVENT_UNFILTERED is forbidden to addons in 12.0, so
CombatTracker is rewritten on C_DamageMeter with baseline/delta reads, secret
value guards and per-boss snapshots out of combat.
Encounters: CHALLENGE_MODE_COMPLETED has no payload; keystone results now come
from C_ChallengeMode.GetChallengeCompletionInfo. Records store instance name,
season, character, affixes, keystone map/time/limit/upgrades, practice flag and
boss kills. Non-M+ runs with boss kills resolve as completed instead of left.
Member absence is time-based (6s) and rejoins clear leftAt. Encounter start
retries while the roster is unresolvable at zone-in, and a boss kill with no
running encounter starts one so the kill is counted.
Realm: GetNormalizedRealmName() is nil on instance loading screens, which
crashed the reputation broadcast and left encounters unstarted. All realm
fallbacks use Voidstorm.Utils.RealmName (polyfilled for older cores) and skip
the unit instead of building a bare Name- key.
Comm: group sends through the Voidstorm core prefix with legacy receive kept,
INSTANCE_CHAT for instance-only groups, public score clamp, self-score
rejection, secret guards. Guild sync moves to the core prefix as well.
Also: ordered event bus, Blizzard Settings panel with real defaults, DB
migrations (realmless dedupe, false leftAt, instance names), deprecated
GetSpecialization/SendChatMessage replaced, weekly reset via
GetWeeklyResetStartTime, LFG applicant tooltips via HookScript, Bindings.xml
header/category attributes (and it must not be listed in the TOC), auto-export
off by default, luacheck config and lint workflow. Version 1.2.0. - feat: complete enUS localization and pass all strings through ns.L
Every user-facing string in the addon now goes through the locale table;
enUS grows to 350+ keys and the deDE/koKR/ruRU/zhCN stubs fall back to it. - fix: commit missing ClearCommCache in ReputationData and simplify Bindings.xml
ReputationData.lua was missing the ClearCommCache function and GROUP_LEFT
listener on HEAD despite being part of the original bugfix plan. Also removes
redundant header and runOnUp attributes from Bindings.xml. - feat: colorblind accessibility mode with orange/blue palette and shape indicators
Adds settings.accessibility.colorblindMode toggle. When enabled:- Swaps positive/negative colors from red/green to orange/blue
- Prepends shape indicators: star for favorites/positive, triangle for avoid/negative
- Applied via S.ApplyColorblindMode() which swaps the S.COLORS table
- Shape helpers: S.FavoriteIndicator(), S.AvoidIndicator(), S.PositiveIndicator(), S.NegativeIndicator()
- TooltipHook avoid/favorite lines use shape indicators
- feat: localization framework with enUS base and 4 locale stubs
Adds ns.L locale table with metatable fallback (missing keys return the key
itself). enUS.lua defines all ~130 string keys. deDE, ruRU, zhCN, koKR stubs
created with commented translations ready for community contribution.
SettingsTab and TooltipHook converted to use L["key"] lookups as reference
implementation. Other files can be converted incrementally. - feat: public addon API for third-party integration
Exposes VPL.API (also available as _G.VoidstormPartyLedger.API) with stable
methods: GetReputation, GetCommunityScore, IsAvoided, IsFavorite, GetNote,
GetEncounterHistory, GetGroupCount, GetCurrentEncounter, GetPlayerAlerts,
GetKeyPrediction, RegisterCallback, UnregisterCallback. All methods return
copies/primitives, never internal table references. API version 1. - fix: address Phase 3 review findings
- Guard nil timestamp in GetPlayerEncounters sort (crash prevention)
- Fix KeyPredictor score inflation: penalty now applies after base confidence
- Add scroll frame to StatsTab so bottom sections aren't clipped
- Guard StatsTab Refresh against partial initialization
- Remove dead MakeStatWide function
- Fix misleading "pulls" label to "runs" in DeathAnalysis
- feat: M+ key success predictor based on group composition history
Estimates timed completion probability for current M+ group by analyzing each
member's historical timed rate, with extra weight for runs at similar key
levels. Accounts for unknown members with a confidence penalty. Accessible
via /vpl predict and programmatically via VPL.KeyPredictor.GetPredictionText(). - feat: death analysis showing per-boss death patterns in player profiles
New DeathAnalysis module aggregates death data from combatStats across all
encounters for a player. Shows deaths/run average, deathless run rate, and
top 3 worst bosses by death rate. Displayed in PlayerProfile between tags
and notes sections. - feat: CSV export for encounters and players via /vpl export csv
Writes two CSV strings to VoidstormPartyLedgerExportDB SavedVariable:
csv_encounters (id, date, content, outcome, duration, key level, group size)
and csv_players (name, class, groups, last seen, favorite, avoided, note).
Companion app or external tools can parse these from the .lua file. - feat: personal stats dashboard tab with performance analytics
New 5th tab showing: overview stats (encounters, completion rate, unique
players), M+ metrics (timed rate, avg/highest key), content breakdown
table, top 5 most-grouped players, and role distribution. Refreshes on
tab selection. Single-pass iteration over encounters for all calculations. - fix: rename local IsInGuild to prevent infinite recursion
The local function shadowed the global WoW API IsInGuild(), causing a stack
overflow. Renamed to PlayerIsInGuild() which correctly calls the global. - feat: guild reputation sharing via GUILD addon channel
Add GuildSync module that broadcasts reputation scores to guild members via the GUILD addon message channel, storing received scores with a 1.5x trust multiplier in VPL.db.guildScores. - feat: weekly digest summary printed on first login after reset
Shows a one-line chat summary 8 seconds after login with key stats from the
past week: run count, timed %, average key level, new favorites/avoids.
Only fires once per reset period (tracked via _lastDigestReset in DB).
Uses C_DateAndTime.GetWeeklyResetTime for region-correct reset timing. - feat: track player spec per encounter
Captures specialization via GetInspectSpecialization (party/raid members) and
GetSpecializationInfo (self) when building group roster. Spec is stored in
encounter member data and backfilled on roster updates if initially unavailable.
Displayed in PlayerProfile role badge and HistoryBrowser member rows. - feat: smart LFG alerts showing encounter history in tooltips
- feat: tooltip settings take effect immediately without /reload
Added SETTINGS_CHANGED event fired from SettingsTab toggles. TooltipHook now
dynamically registers/unregisters UPDATE_MOUSEOVER_UNIT and guards
AddReputationToTooltip with a live settings check. Permanent hooks (like
TooltipDataProcessor) still fire but exit early when disabled. - refactor: restructure LFG hook with early returns and clearer flow
Flattened nested if-blocks into early returns, moved hookedEntries guard
after overlay updates (since overlays must update on every call but hook
only registers once), added comments for the three logical sections. - feat: record backup marker on version upgrade before migrations
Stores a lightweight marker (_lastBackup) with timestamp, previous version,
and encounter count before any destructive migration runs. Enables detection
of whether a migration caused data loss. - feat: protocol v2 with escaped field serialization for addon messages
- fix: invalidate display list on sort column change, guard nil favorites/avoid
Sort header clicks were not calling InvalidateDisplayList(), so the cached
display list kept its old sort order — a regression from the caching change.
Also added nil guards for favorites/avoid tables in reputation pruning to
prevent errors on fresh installs or corrupted databases. - fix: display raid completion pct and cache display list to reduce sort overhead
- fix: guard against nil Voidstorm reference in tooltip mouseover handler
VS.Utils.FullName crashed if the Voidstorm parent addon wasn't loaded.
Now the handler returns early with cleared state if VS is unavailable. - fix: prune stale reputation scores on load to prevent SavedVariables bloat
- fix: decouple CombatTracker from GROUP_ROSTER_UPDATE to prevent data loss
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com - fix: relay GROUP_LEFT through internal event bus so addonCommCache is wiped on group leave
VPL:Fire("GROUP_LEFT") was never called after the WoW GROUP_LEFT event
fired on GroupTracker's event frame, causing ReputationData.lua's
addonCommCache listener to never trigger and the cache to grow
unbounded for the entire session. Fire is placed after EndEncounter
so the encounter is saved before the cache is wiped. - feat: category ratings, GDPR cleanup, export optimization, Blizzard settings
- TagSystem: add CATEGORIES grouping (Performance, Attitude, Reliability) with tag mapping
- ReputationScore: add CalculateByCategory() for per-category reputation breakdown
- PlayerProfile: show category score breakdown (Performance/Attitude/Reliability/Issues)
- VoidstormReputationSync: remove 73 hardcoded EU player names (GDPR compliance),
replace with empty seed structure populated by companion app - DataExport: add dirty flag, only rebuild payload on logout if data actually changed
- Core: register with Blizzard Interface Options panel
- Core: improve missing-core error to StaticPopup dialog with install instructions
- Fix critical bugs: settings toggle, memory leak, reputation farming, UX improvements
- SettingsTab: fix double-toggle bug where clicking toggle fires both row and widget handlers
- RatingPopup: use frame pooling instead of SetParent(nil) (fixes memory leak)
- AddonComm: re-broadcast reputation when group grows so newcomers receive data
- CombatTracker: pre-populate guidToName from group roster at tracking start
- ReputationScore: add per-tagger cap (max 3 positive tags) to prevent score farming
- ReputationOverlay: set minimum height at creation to prevent 0-height render
- Core: show StaticPopup dialog instead of plain print when Voidstorm core is missing
- PlayersTab: make column headers clickable for sorting (Name, Groups, Last Seen, Score)
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
- Add pagination, column tables, keybinds, protocol versioning, and UI hardening
- Harden addon comms, fix multi-dungeon logging, add Cyrillic support and data management
- Fix multi-dungeon logging bug (completedThisRun not resetting between dungeons in same party)
- Fix unsafe table iteration during pairs(), StaticPopup closure leaks, tooltip hook, raid player duplication
- Add Noto Sans fonts for Cyrillic/Latin/Greek text rendering
- Harden AddonComm: sender-self-only validation, group membership check, tag whitelist, size cap
- Add protocol versioning (v1) with backward compat for unversioned messages
- Add minimum signal threshold (hasEnoughData) for reputation display across all UI
- Auto-cleanup orphaned tags when encounters are pruned past 500 cap
- CombatTracker uses GUIDs as in-memory keys to avoid cross-realm name collisions
- Include combatStats in companion export, auto-strip from encounters older than 7 days
- Add /vpl delete and /vpl clearcommunity commands
This mod has no additional files