File Details
DeathNotificationLib V5
- R
- Feb 25, 2026
- 5.76 MB
- 8
- 2.5.5+1
- Classic + 1
File Name
DeathNotificationLib.zip
Supported Versions
- 2.5.5
- 1.15.8
V5 — 2026-02-24
Critical Performance Fix: Blizzard HistoryKeeper Memory Leak Mitigation
- Installed
ChatFrame_AddMessageEventFilterforCHAT_MSG_CHANNEL,CHAT_MSG_CHANNEL_NOTICE,CHAT_MSG_CHANNEL_NOTICE_USER,CHAT_MSG_CHANNEL_JOIN, andCHAT_MSG_CHANNEL_LEAVEto suppress both the sync channel (hcdeathlogsyncchannel*) and the death-alerts channel (hcdeathalertschannel*) before they reach Blizzard's chat pipeline - Root cause: Blizzard's
HistoryKeeper.lua(ChatHistory_GetAccessID) creates a permanent table entry for every unique(chatType, chatTarget, chanSender)tuple — these are never garbage-collected. On a high-traffic channel with hundreds of unique senders, this causes monotonically growing memory + CPU cost even when the addon is completely disabled - The filter runs in the
chatFilterstable (checked at line ~1126 ofChatFrame_MessageEventHandler), which fires beforeChatHistory_GetAccessID(line ~1476),GetColoredName, andAddMessage— short-circuiting the entire Blizzard chat pipeline for our channels - The filter is installed at file-load time in
~Init.lua(earliest load), so it is active even if the player was still in a channel from a previous session - This eliminates the lag that players reported even with
sync_enabled = falseor the addon disabled — the issue was Blizzard-side overhead processingCHAT_MSG_CHANNELevents, not addon code
Sync: Channel-Busy Cooldown (prevent simultaneous E$ streams)
- Added
CHANNEL_BUSY_COOLDOWN(30s): when E$ entry traffic is seen on the sync channel, new sync triggers are suppressed for 30 seconds - Previously, multiple behind-peers could simultaneously enter
COLLECTING_WATERMARKS→JITTER_WAITand send M$ requests to different responders before any E$ appeared on the channel, causing overlapping entry streams that flooded the channel - The cooldown is checked in
handleSyncWatermark(before entering collect phase) and_syncPickPeerAndJitter(before entering jitter phase), ensuring only the first requester triggers a response while everyone else passively consumes the entries
Performance
predictSource()is no longer called during sync entry ingestion (createEntrywithSOURCE.SYNC); the expensive heatmap ring-search andC_MapAPI lookups are deferred until an entry is first displayed, where all three display paths (search log, minilog, stats) already compute it lazily — eliminates the primary cause of frame-rate drops reported by users syncing large databases
Sync Channel Lifecycle
joinSyncChannel()no longer gates onanySyncEnabled()— the sync channel is always joined so that watermark broadcasts carrying addon-version upgrade hints are received even when syncing is disabled_startSyncWatermarkTicker()interval calculation no longer filters onisSyncEnabled;broadcastWatermark()already skips addons with sync off, so the ticker is harmless when no addons sync and starts broadcasting immediately if sync is enabled mid-session
New: auto_hide_chat_channels Setting
- New opt-out setting (default
true): when any attached addon sets it tofalse,hideChannelFromChatFrames()becomes a no-op, leaving addon channels visible in chat frames for debugging - Added to the
DNL_Settingstype annotation
New: Addon Version Notifications
- Watermark broadcasts now include the registering addon's semantic version string as a 5th field (backward-compatible — old clients send an empty field)
- After 3 unique peers advertise a newer version, a chat notification is printed and all
HookOnNewerVersioncallbacks are fired - New public API:
GetNewerAddonVersion(addonName)— returns the newest detected version string, or nilHookOnNewerVersion(fn)— registers a callbackfn(addonName, newerVersion, currentVersion)that fires when a newer version is confirmedFireNewerVersionHook(addonName, newerVersion, currentVersion)— test helper to manually trigger the hook at runtime
AttachAddonnow accepts anaddon_versionfield (e.g."0.4.1") to register the local addon's version
New: Social-Channel Version Broadcast (~VersionCheck.lua)
- New module broadcasts the addon version on social channels (PARTY, RAID, GUILD, INSTANCE_CHAT) when the player joins a group, raid, instance, or logs in while in a guild
- Uses a dedicated addon-message prefix
HCDeathVerto avoid interfering with the death-alert or sync protocols - Wire commands:
V$TAG~version~(version announcement) andN$TAG~version~(newer-version whisper notification) - On receiving a version announcement:
- If the remote version is newer: immediately shows an update-available chat message and fires
HookOnNewerVersioncallbacks (no multi-peer threshold — a single sender on a trusted channel is sufficient) - If the remote version is older: whispers back the local version via
N$so the sender also learns about the update
- If the remote version is newer: immediately shows an update-available chat message and fires
- Per-session dedup prevents the same version notification from appearing more than once
- 120-second cooldown per channel type prevents spam on rapid group changes
- Triggered by
PLAYER_ENTERING_WORLD(login/reload) andGROUP_ROSTER_UPDATE(group composition changes) - Registered the
HCDeathVerprefix viaC_ChatInfo.RegisterAddonMessagePrefixin~Events.lua CHAT_MSG_ADDONdispatch in~Events.luaroutesHCDeathVermessages to_dnl.handleVersionCheckAddonMessage
Protocol Hardening
- Messages from protocol versions newer than the local version are now silently rejected in all three receive paths: death broadcasts (
~Cache), query ACKs (~Events), and sync entries (~Sync) - Removed the old protocol-version upgrade chat hint (replaced by the more accurate per-addon version notification above)
New: Watchlist Channel Query (WATCHLIST_QUERY / command "6")
- New protocol command broadcasts comma-separated watchlist names over the death alerts channel (
6$TAG~name1,name2,...) - Every connected addon user receives the query, checks their local DB, and whispers back up to 10 matching death records via the existing
COMM_QUERY_ACK(R$) pathway - Wire format respects the 255-byte limit — names are batched until the budget is exhausted; remaining names are omitted from that message
- Inbound handler validates the tag, ignores self-queries, and skips unknown tags
- New public API:
QueryChannel(names, tag)— queues a batch watchlist query for the realm-wide death channel - New
watchlist_query_queue— drained on user input alongside existing queues (priority: duel requests > watchlist queries > checksums > death pings); stale-entry trimming (58 s max age) covers the queue
Bug Fixes
- Fixed a race condition where deaths arriving via Blizzard's
HARDCORE_DEATHSchannel were discarded when a peer broadcast withsource_id = -1had already been committed — the Blizzard message now upgrades the committed entry'ssource_idto the correct NPC ID and re-fires hooks so addon databases receive the corrected data; previously these deaths were displayed with a heatmap-predicted source (trailing*) even though the real killer was known - Fixed duplicate entries from party/sync sources — multiple root causes in the dedup pipeline:
fletcher16produces different checksums for the same death when guild or source_id differs between reporters; all dedup layers now use name-based matching (vialru_by_name) in addition to checksum matching- Outbound broadcast dedup (
~Broadcast):broadcastDeath()now checkslru_by_namebefore computing a checksum — if the same player name is already in the LRU within the dedup window, the broadcast is suppressed and the data is merged into the existing entry via quality-aware merge; prevents multiple party members from each sending a separate broadcast for the same death - Inbound broadcast dedup (
~Cache):handleDeathBroadcast()equal-or-lower quality path now always merges into the existing entry and returns, regardless of whether the existing entry has committed — previously, an uncommitted equal-quality entry with a different checksum fell through and created a parallel LRU entry that committed as a duplicate - Sync ingestion dedup (
~Sync):_processSyncEntry()now pre-checks the target addon's DB (viadb_map) for an existing entry with the same player name within the dedup window before callingcreateEntry; matching entries are merged instead of duplicated NAME_DEDUP_WINDOWincreased from 60 s to a dynamic value across all layers
- Fixed late quality-upgrade race — when network/CPU timing spread caused a higher-quality broadcast (e.g. SELF from the dying player) to arrive after a lower-quality PEER entry had already committed, the better data was silently discarded; the quality-upgrade path in
handleDeathBroadcastnow detects the already-committed state, merges the superior data in-place, and re-firescreateEntrywith the existing checksum so addon hooks overwrite the DB entry with the best available information
Internal
- New semver utilities:
parseVersion(ver)andcompareVersions(a, b)on the internal_dnlnamespace DNL_RegisteredAddongainsaddon_versionandnewest_detected_versionfields

