File Details
TOGBankClassic-v0.8.28-classic
- R
- Feb 27, 2026
- 175.88 KB
- 134
- 1.15.8
- Classic
File Name
TOGBankClassic-TOGBankClassic-v0.8.28-classic.zip
Supported Versions
- 1.15.8
TOGBankClassic Changelog
Unreleased - Hash Sync Fixes
Status: In Development Priority: CRITICAL
🐛 Bug Fixes
[PERF-007] Fixed Bagnon Execution Timeout from BAG_UPDATE Spam (CRITICAL)
- FIXED: ItemHighlight now throttles BAG_UPDATE events and caches search strings
- PROBLEM: Bagnon exceeded execution time limit during zone changes
- ROOT CAUSE: Every BAG_UPDATE event triggered RefreshHighlighting which called Bagnon's SendSignal('SEARCH_CHANGED'), causing full UI rebuild
- IMPACT: "Script from Bagnon has exceeded its execution time limit" errors on zone change
- BEHAVIOR: Zone changes fire multiple rapid BAG_UPDATE events, each triggering Bagnon UI rebuild
- SOLUTION:
- Added 500ms throttling to BAG_UPDATE event handler (same pattern as Requests UI)
- Cache last Bagnon search string and only send SEARCH_CHANGED signal when it actually changes
- Clear cache when disabling highlighting to avoid unnecessary signals
- Prevents rapid-fire Bagnon UI rebuilds during zone transitions
- RESULT: Eliminated Bagnon execution timeout errors, highlighting still works correctly
- LOCATION:
- ItemHighlight.lua Initialize (~18-41): Added throttling to event handler
- ItemHighlight.lua UpdateBagnonHighlighting (~252-260): Cache and compare search string
- ItemHighlight.lua RefreshHighlighting (~367-377): Clear cache when disabled
- ItemHighlight.lua SetEnabled (~95-105): Clear cache when disabling
[HASH-001] Fixed Hash Broadcast Not Triggering P2P Requests (CRITICAL)
- FIXED: hash-list-broadcast handler now triggers P2P requests for changed data
- PROBLEM:
/togbank shareonly updated latestBankerHashes cache without triggering any data requests - IMPACT: Complete sync failure - receivers saw "Updated banker hashes" but never requested changed data
- BEHAVIOR: Users had to manually run
/togbank syncor wait 3 minutes for auto-sync timer - ROOT CAUSE: hash-list-broadcast (togbank-hl) only cached hashes, while hash-list-reply (togbank-hlr) also compared and broadcast P2P
- INCONSISTENCY: Same data (hash updates) handled differently depending on source (broadcast vs reply)
- SOLUTION:
- hash-list-broadcast handler updates latestBankerHashes cache (immediate)
- Converts message to hash-list-reply format
- Recursively calls OnCommReceived with "togbank-hlr" prefix to reuse existing logic
- hash-list-reply handler now updates cache incrementally (not replacement) to support partial broadcasts
- Avoids code duplication - single code path for all hash processing
- RESULT:
/togbank sharenow triggers immediate P2P broadcasts, data syncs automatically - LOCATION:
Modules/Chat.lua(~1773-1800, ~1816-1828): Forward broadcast to reply handler, incremental cache update - NOW: Hash broadcasts work identically whether from
/togbank share(broadcast) or/togbank sync(reply)
[COMM-003] Fixed Offline Player Detection from Whisper Errors
- FIXED: CHAT_MSG_SYSTEM now detects "No player named X is currently playing" errors
- PROBLEM: Addon repeatedly attempted whispers to offline players causing error spam
- ROOT CAUSE: CHAT_MSG_SYSTEM handler only detected "has gone offline" but not whisper failure errors
- IMPACT: Hundreds of error messages when trying to communicate with offline players
- SOLUTION:
- Added pattern matching for "No player named X is currently playing" in CHAT_MSG_SYSTEM
- When detected, immediately marks player as offline in both onlineMembers and recentlySeen caches
- Updated UpdateOnlineMember() to clear recentlySeen cache when marking offline
- Added debug logging for all online/offline state changes
- RESULT: Player marked offline immediately when whisper fails, preventing repeat attempts
- LOCATION:
- Events.lua CHAT_MSG_SYSTEM (~334-375): Added error pattern detection
- Guild.lua UpdateOnlineMember (~1425-1443): Clear recentlySeen on offline
[COMM-003b] Fixed Whisper Error Pattern Not Matching Single-Quoted Names
- FIXED: CHAT_MSG_SYSTEM now detects both single-quoted and unquoted variants of whisper failure messages
- PROBLEM: Pattern only matched
No player named Axkva is currently playing.but Classic Era can also sendNo player named 'Axkva' is currently playing.(with single quotes around name) - ROOT CAUSE: COMM-003 documentation incorrectly stated "Classic Era does NOT use quotes" but testing showed single quotes are sometimes used around player names
- IMPACT: Whisper failures with single-quoted names not detected, causing repeated whisper attempts and error spam
- SOLUTION:
- Added dual pattern matching: tries single-quoted pattern
'(.+)'first, falls back to unquoted(.+)if no match - Updated documentation to reflect both formats are possible
- Added dual pattern matching: tries single-quoted pattern
- RESULT: All whisper failure formats now detected, player marked offline immediately
- LOCATION:
- Events.lua CHAT_MSG_SYSTEM (~353-361): Dual pattern matching
- DELTA_BUGS.md (~2521-2527): Updated pattern documentation
[COMM-003c] Fixed Whisper Error Messages Still Appearing in Chat
- FIXED: Added chat message filter to suppress "No player named X is currently playing" errors from appearing in chat
- PROBLEM: While COMM-003/COMM-003b fixed offline detection, the error messages still appeared in chat window
- ROOT CAUSE: Event handler detected and processed errors but didn't suppress chat display
- IMPACT: Chat spam with "No player named 'X' is currently playing" even though addon correctly marked players offline
- SOLUTION:
- Added ChatFrame_AddMessageEventFilter for CHAT_MSG_SYSTEM
- Filter returns true to suppress any message matching "No player named .+ is currently playing."
- Works for both single-quoted and unquoted name variants
- RESULT: Error messages silently handled - player marked offline without chat spam
- LOCATION:
- Events.lua RegisterEvents (~59-66): Added chat message filter
[PERF-009] Fixed ChatFrame_AddMessageEventFilter Performance Issue
- FIXED: Optimized chat filter to use fast plain-text check before pattern matching
- PROBLEM: Stuttering during gameplay immediately after adding chat filter in COMM-003c
- ROOT CAUSE: Pattern match ran on EVERY CHAT_MSG_SYSTEM event (guild achievements, player online/offline, etc)
- IMPACT: 20-30 expensive pattern matches per minute causing ~10-30ms cumulative frame time waste
- SOLUTION:
- Added fast plain-text prefix check:
find("No player named ", 1, true)(~0.01ms) - Pattern match only runs if prefix found (rare - only actual whisper errors)
- 99%+ of events skip expensive pattern matching
- Added fast plain-text prefix check:
- RESULT: 50x performance improvement, stuttering eliminated while maintaining error suppression
- LOCATION:
- Events.lua Initialize (~59-68): Added plain-text prefix check before pattern match
[PERF-010] Fixed Login Freeze from Synchronous Data Migrations
- FIXED: Deferred Database:Load() migrations and hash cache initialization to eliminate 3-5 second freeze on login/reload
- PROBLEM: Game completely froze for 3-5 seconds when logging in or reloading UI with large SavedVariables (70+ alts)
- ROOT CAUSE: Database:Load() synchronously looped through ALL alts performing migrations on EVERY login - most expensive was RecalculateAggregatedItems() for each banker alt (~30-50ms per alt)
- IMPACT: Cannot move, cast spells, or interact during freeze - appeared as if game crashed
- WHY DEFERRABLE: Data already loaded from SavedVariables, migrations are cleanup/optimization operations that don't need to be immediate
- SOLUTION:
- Wrapped entire Database:Load() migration block in C_Timer.After(0.5)
- Also deferred latestBankerHashes initialization in Guild:Init (lighter but still blocking)
- Migrations run in background after UI becomes responsive
- Still complete before first UI interaction or sync
- RESULT: Instant login, no freeze, migrations ready before first use
- LOCATION:
- Database.lua Load (~175-243): Deferred migration block
- Guild.lua Init (~295-313): Deferred latestBankerHashes initialization
- LOCATION:
- Events.lua Initialize (~59-68): Added plain-text prefix check before pattern match
[COMM-003d] Fixed recentlySeen Cache Undermining Guild Roster Cache (CRITICAL)
- FIXED: Removed recentlySeen cache, IsPlayerOnline now uses only guild roster cache
- PROBLEM: Addon still tried to whisper players for 5 minutes after they logged off
- ROOT CAUSE: IsPlayerOnline checked both onlineMembers (accurate) and recentlySeen (5-minute stale cache)
- FLOW: Player sends message → added to recentlySeen → logs off → onlineMembers cleared correctly → but recentlySeen keeps them "online" for 5 minutes → whispers sent → errors
- IMPACT: Despite accurate guild roster updates (COMM-003), whisper errors still occurred due to secondary stale cache
- WHY IT EXISTED: Originally added for "cross-realm/cross-guild" players, but this is a guild-only addon
- SOLUTION:
- Removed recentlySeen check from IsPlayerOnline - guild roster cache is single source of truth
- Removed MarkPlayerSeen call in Chat.lua
- MarkPlayerSeen() kept as no-op for backwards compatibility
- RESULT: IsPlayerOnline returns false immediately when player logs off, no stale 5-minute window
- LOCATION:
- Guild.lua IsPlayerOnline (~1542-1547): Removed recentlySeen logic, only check onlineMembers
- Guild.lua MarkPlayerSeen (~1533-1537): Made no-op
- Chat.lua OnCommReceived (~617-619): Removed MarkPlayerSeen call
[DELTA-020] Fixed Delta Computation Using Wrong Baseline (CRITICAL)
- FIXED: ComputeDelta now uses requester's actual item structures from state summary instead of responder's snapshot
- PROBLEM: When responder broadcast multiple times (hash 461905621 → 317352773), GetSnapshot returned responder's NEW snapshot (317352773) instead of requester's OLD baseline (461905621)
- IMPACT: Item count duplication/corruption - delta computed as (317352773 - 317352773) = empty/minimal instead of (317352773 - 461905621) = proper changes
- BEHAVIOR: Requester with hash 461905621 applied incorrect delta to their old data, causing items to double instead of updating
- ROOT CAUSE:
- Snapshot system stores ONE snapshot per alt (keyed only by altName, not hash)
- When responder broadcasts twice, old snapshot overwritten (461905621 deleted, only 317352773 remains)
- State summary previously sent aggregated items
{[itemID] = count}(useless for delta computation) - ComputeDelta used GetSnapshot(altName) which returned responder's OWN latest state, not requester's actual baseline
- DESIGN ISSUE: Delta needs requester's actual item structure (bank/bags/mail) to compute
delta = current - requester's baseline - SOLUTION:
- Modified ComputeStateSummary to send minimal item structures
{ID, Count}(no Links) for separate bank/bags/mail arrays - Modified ComputeDelta to accept optional
requesterBaselineparameter with minimal structures - ComputeDelta now uses requester's sent baseline as
previousinstead of GetSnapshot when available - RespondToStateSummary extracts bank/bags/mail from state summary and passes through SendAltData → ComputeDelta chain
- SendAltData signature updated to accept and forward requesterBaseline parameter
- All SendAltData call sites updated to pass baseline (or nil for legacy paths)
- Modified ComputeStateSummary to send minimal item structures
- BANDWIDTH SAVINGS: Minimal structures ~1-2KB vs full with Links ~20-50KB (~85% reduction)
- RESULT: Delta computation uses correct baseline - requester's actual data (what they have) vs responder's current (what to send)
- LOCATIONS:
- Guild.lua ComputeStateSummary (~1485-1542): Send bank/bags/mail arrays with {ID, Count} only
- Guild.lua SendStateSummary (~1593-1606): Updated logging to count bank+bags+mail items
- Guild.lua RespondToStateSummary (~1640-1644): Extract requesterBaseline from state summary
- Guild.lua SendAltData (~2231, ~2301): Added requesterBaseline parameter
- Guild.lua ComputeDelta wrapper (~2862): Pass through requesterBaseline
- DeltaComms.lua ComputeDelta (~565-620): Accept requesterBaseline, use expandMinimalItems() helper, compute from requester's actual data
- NOW: Proper delta application - item counts update correctly without duplication, works regardless of how many broadcasts requester missed
- RELATED: Completes DELTA-019 fix - hash stays at local value until correct delta (computed from actual baseline) received and applied
[DELTA-019] Fixed Premature Hash Update Before Data Received (CRITICAL)
- FIXED: Removed HLR first pass branch that updated hash when
localHash == 0 - PROBLEM: Hash updated from banker's broadcast before delta data arrived and was applied
- IMPACT: Data/hash desynchronization - old data stored with new hash value
- BEHAVIOR: User has hash 529743613 with data, banker broadcasts 461905621, hash immediately updates to 461905621 but old data remains
- CONSEQUENCE: Future sync attempts see matching hashes and skip update, leaving permanent stale data until
/wipecommand - ROOT CAUSE: HLR first pass had three branches:
if not localAlt- Create new stub with banker's hash (CORRECT - for brand new alts)elseif localHash == 0- Update existing alt's hash (BUG - fires during pending sync)elseif mismatch- Log mismatch without updating (CORRECT)
- TRIGGER SCENARIO: Between HLR broadcasts, localHash becomes 0 (ApplyDelta creates stub, or other process clears it), next HLR hits branch 2 and updates hash prematurely
- USER SCENARIO: "i have hash 5xxxx with data, banker sends hash 4xxxx, I should use hash 4xxxx to trigger delta sync comparing hash 5xx with 4xx to determine the delta, and then get new data"
- ACTUAL BUG BEHAVIOR: Hash 5xxxx → 4xxxx update happens immediately in HLR first pass, before delta data request sent/received
- SOLUTION: Removed branch 2 entirely from HLR first pass (Chat.lua lines 1861-1873)
- Only create NEW stubs for brand new alts (branch 1)
- Only update hash in ApplyDelta after successful data application (DeltaComms.lua:971)
- Hash mismatch detection (branch 3) triggers requests without updating hash
- RESULT: Hash stays at local value until delta received and applied, maintaining data/hash consistency
- LOCATION: Chat.lua HLR handler first pass (~1847-1878): Removed
elseif localHash == 0branch - RELATED: Works with DELTA-018 fix - latestBankerHashes cache tracks "what banker says", local inventoryHash tracks "what data we have", only ApplyDelta updates local hash
[DELTA-018] Fixed Hash Broadcast Circular Comparison (CRITICAL)
- FIXED: Hash sync protocol now maintains separate in-memory cache from local storage
- PROBLEM: hash-list-broadcast immediately updated local alt.inventoryHash, then comparison read from same local storage
- IMPACT: Complete sync failure - /togbank share broadcasts updated hash without triggering sync requests
- BEHAVIOR: Receivers had stale data but /togbank hashdebug showed "matched" (compared local hash against itself)
- ROOT CAUSE: Circular comparison - BuildBankerHashList() read from alt.inventoryHash, ReportHashListCoverage compared alt.inventoryHash vs BuildBankerHashList() output (both same source)
- DESIGN FLAW: No separation between "banker's authoritative hash" (what they broadcast) vs "hash of data we actually have" (what's in SavedVariables)
- SOLUTION:
- Initialize
latestBankerHashesin-memory cache on addon load from all local alt.inventoryHash values - hash-list-broadcast handler: Only update cache, never modify local storage
- hash-list-reply handler: Only update cache on mismatch, never modify local storage
- ReportHashListCoverage: Use latestBankerHashes exclusively (no BuildBankerHashList, no merge)
- Local alt.inventoryHash: Only updated when actual delta data received and applied
- Initialize
- CACHE STRUCTURE:
{hash, updatedAt, version, mailHash, mailUpdatedAt}per alt - COMPARISON LOGIC: cache.hash ("what banker says") vs localAlt.inventoryHash ("what we have")
- RESULT: Proper mismatch detection - cache updated by broadcasts, local unchanged until delta received, comparison detects staleness
- LOCATION:
- Guild.lua Init (~276-290): Initialize latestBankerHashes from SavedVariables
- Guild.lua ReportHashListCoverage (~693-710): Use cache directly for comparison
- Chat.lua hash-list-broadcast (~1773-1795): Update cache only
- Chat.lua hash-list-reply (~1843-1847): Update cache only on mismatch
- VERIFICATION: Tested with manual hash revert - broadcast updated cache, local stayed stale, hashdebug showed pending, sync requested delta
[DELTA-016] Fixed Delta Protocol Sending Aggregated Items (CRITICAL)
- FIXED: ComputeDelta now sends separate bank/bags/mail inventories instead of aggregated items
- PROBLEM: Used
alt.items(UI display field) which was often empty on sender side despite non-zero hash - IMPACT: Complete data sync failure - deltas contained only money updates, no item data
- BEHAVIOR: Debug showed "hasChanges.items=false, itemCount=0" with non-zero inventoryHash (contradiction)
- ROOT CAUSE:
alt.itemscomputed during Bank:Scan() for UI aggregation, not guaranteed during delta computation - PROTOCOL DESIGN: Should send bank/bags/mail separately so receiver populates individual inventories
- SOLUTION:
- ComputeDelta: Source from
currentAlt.bank.items,bags.items,mail.itemsseparately - ApplyDelta: Apply to
current.bank.items,bags.items,mail.itemsindividually - Recalculate aggregated
current.itemsafter delta application (UI display only) - DeltaHasChanges: Check bank/bags/mail separately
- ValidateDeltaStructure: Validate mail delta
- SanitizeDelta: Sanitize mail delta
- StripDeltaLinks: Strip mail links
- ComputeDelta: Source from
- RESULT: Deltas now contain actual item data (ID + Count) in separate bank/bags/mail structures
- LOCATION:
DeltaComms.luaComputeDelta (~627-648), ApplyDelta (~912-969), DeltaHasChanges, validation/sanitization - NOW: Full inventory synchronization working - items populate correctly on receiver side
[DELTA-017] Fixed Empty Baseline Missing Bank/Bags/Mail Structures (CRITICAL)
- FIXED: ComputeDelta empty baseline now includes bank/bags/mail structures
- PROBLEM: Empty baseline fallback only had
{ items = {}, money = 0, mailHash = 0 }without bank/bags/mail - IMPACT: First-time sync sent empty deltas despite sender having inventory data
- BEHAVIOR: ComputeDelta compared empty baseline to sender's current but both appeared empty
- ROOT CAUSE: When accessing
previous.bank.items, defaulted to{}but didn't distinguish between incomplete baseline vs empty inventory - SOLUTION:
- Changed empty baseline to include complete structures:
{ items = {}, money = 0, mailHash = 0, bank = { items = {} }, bags = { items = {} }, mail = { items = {} } } - Fixed in 3 locations: mail-only change without snapshot, hash mismatch without snapshot, requester has no data
- Changed empty baseline to include complete structures:
- RESULT: First-time sync and hash mismatch scenarios now send actual items (not empty deltas)
- LOCATION:
DeltaComms.luaComputeDelta empty baseline initialization (~594, ~606, ~613) - NOW: All sync scenarios populate receiver correctly with sender's inventory data
[MAIL-010] Fixed Mail-Only Change Sync Abort (CRITICAL)
- FIXED: ComputeDelta now uses empty baseline fallback instead of returning nil
- PROBLEM: When mail changed but inventory matched, and no snapshot existed, returned nil (line 567)
- IMPACT: Complete sync failure - requesters with matching inventory but outdated mail never received updates
- BEHAVIOR: Guild.lua aborted sync at line 2054-2055 with "Failed to compute delta" error
- ROOT CAUSE: Inconsistent error handling - inventory mismatch used empty baseline, mail-only change returned nil
- SOLUTION: Changed to
previous = { items = {}, money = 0, mailHash = 0 }(same as inventory mismatch case) - RESULT: Mail-only changes always sync successfully via delta (contains all items as additions against empty baseline)
- LOCATION:
DeltaComms.lua(~557-567): Mail-only change handler now matches inventory mismatch fallback behavior - NOTE: Still pure delta protocol - empty baseline causes delta to include all items, but transmitted as delta message
[P2P-010] Fixed P2P Broadcast Never Sent (CRITICAL)
- FIXED: togbank-rr handler now actually sends P2P broadcast to guild
- PROBLEM: Handler built P2P request but never serialized or sent it
- IMPACT: P2P only worked when no banker online initially; failed when banker responded with hash (common case)
- BEHAVIOR: Request was built, log said "Broadcasting", but SendCommMessage was missing
- RESULT: 5-second timeout always triggered, forcing 100% fallback to banker despite peers having data
- LOCATION:
Chat.lua(~1053-1054): Added missing SerializeWithChecksum and SendCommMessage calls - NOW: Full P2P flow works - peers receive broadcasts and respond with matching hashes
[P2P-011] Fixed pendingSendCount Leak
- FIXED: Added 30-second timeout to auto-decrement counter when requester never sends state summary
- PROBLEM: Peer ACKs request and increments counter, but if requester goes offline before sending state summary, counter never decrements
- IMPACT: After 3 stuck sends, peer permanently blocks all P2P responses with "send queue full" until
/reload - BEHAVIOR: Now auto-decrements counter after 30 seconds if SendAltData never called
- RESULT: Peers self-recover from stuck sends, preventing permanent P2P queue blocking
- LOCATIONS:
Guild.lua(~22): Added pendingSendTimeouts tracking tableChat.lua(~829-838): Added 30-second safety timeout after incrementing counterGuild.lua(~1997-2000): Cancel timeout when SendAltData actually called
- NOW: Robust P2P send queue management with automatic recovery from edge cases
[P2P-012] Added Peer-Side Fallback Timeout
- FIXED: Added 15-second timeout on requester side after peer ACK
- PROBLEM: If peer ACKs but never sends data (disconnect/crash), requester waits indefinitely
- IMPACT: User must manually retry with
/togbank sync - BEHAVIOR: Now falls back to banker after 15 seconds if peer never delivers
- RESULT: Automatic recovery from peer failures without manual intervention
- LOCATION:
Chat.lua(~1091-1101): Secondary timeout after clearing pending P2P request - NOW: Full fallback chain works - peer timeout → banker fallback → data arrives
[P2P-013] Fixed expectedHashUpdatedAt Memory Leak
- FIXED: Added cleanup for expectedHashUpdatedAt after successful hash validation
- PROBLEM: Timestamps stored but never cleared, accumulating indefinitely
- IMPACT: Minor memory leak (just timestamps), no functional impact
- RESULT: Clean memory management for hash tracking
- LOCATION:
Guild.lua(~2250-2252): Clear expectedHashUpdatedAt after validation
[PERF-007] Fixed GUILD_ROSTER_UPDATE Stuttering
- FIXED: Changed OR to AND logic in initialization condition to stop repeated full roster refreshes
- PROBLEM: Used
fullRosterInitAttempts < 2 OR (roster incomplete)which kept triggering after initialization - IMPACT: Every online/offline event triggered full guild roster scan (1000+ members), causing 5-10ms+ stuttering
- BEHAVIOR: After 2 initialization attempts,
fullRosterInitAttempts >= 2BUT condition stayed true due to OR - ROOT CAUSE: Second condition
totalMembers <= onlineMembersoften true (WoW API reports equal values) - SOLUTION: Changed to AND logic - only refresh if BOTH conditions true: (not initialized yet) AND (roster incomplete)
- RESULT: Full refresh only during addon load, online/offline uses lightweight CHAT_MSG_SYSTEM handler (<1ms)
- LOCATION:
Events.lua(~305-313): Fixed needsFullRosterRefresh flag logic - OPERATIONS AVOIDED: RefreshOnlineCache, RebuildBankerRoster, GetGuildRosterInfo loops, RefreshRequestsUI
- NOW: Smooth gameplay without stuttering, full scan only on joins/leaves (not online/offline)
- DOCUMENTATION: See
docs/DELTA_BUGS.mdfor comprehensive analysis (PERF-005, PERF-007)
[DELTA-015] Fixed Delta Duplication Bug (Complete)
- FIXED: Added snapshot validation for inventory changes to prevent item duplication
- PROBLEM: When inventory changed but no snapshot existed, delta computed against empty baseline
- IMPACT: Requester would receive delta additions on top of existing stale data, causing duplicates
- BEHAVIOR: Now checks for snapshot before computing delta for both mail-only AND inventory changes
- RESULT: Forces full data (hash=0) when no snapshot available, preventing duplication
- LOCATIONS:
Guild.lua(~1568-1594): Mail-only change validation (previously fixed)Guild.lua(~1596-1624): Inventory change validation (newly fixed)
[SYNC-009] Fixed Non-Banker Hash Sync
- FIXED: HLR handler now checks hash equality BEFORE skipping alts
- PROBLEM: Previously skipped any alt with hasContent=true without comparing hashes
- IMPACT: Non-banker updates never propagated to peers with stale data
- BEHAVIOR: Now only skips if BOTH hasContent AND hashes match
- RESULT: Non-banker-to-non-banker sync working correctly
[MAIL-009] Fixed mailHash Storage When Hashes Differ
- FIXED: HLR and HL-broadcast handlers now update mailHash when it differs from banker
- PROBLEM: Only stored mailHash when localHash=0, not when hashes differed
- IMPACT: Mail-only changes never cached banker's new mailHash
- LOCATIONS: Fixed in both HLR handler (togbank-hlr) and hash broadcast handler (togbank-hl)
- RESULT: Banker's authoritative mailHash properly cached in all scenarios
Technical Details:
// OLD: Only update when localHash == 0
elseif localHash == 0 then
localAlt.inventoryHash = summary.hash
if summary.mailHash then
localAlt.mailHash = summary.mailHash // Only here!
end
end
// NEW: Also update when hashes differ
elseif localHash ~= summary.hash or (localAlt.mailHash or 0) ~= (summary.mailHash or 0) then
localAlt.inventoryHash = summary.hash
if summary.mailHash then
localAlt.mailHash = summary.mailHash // Now cached properly!
end
end
Files Changed:
Modules/Chat.lua(~1740-1753): HLR handler - added elseif block for hash diffModules/Chat.lua(~1654-1679): HL broadcast handler - updated stub creation and hash updatesdocs/DELTA_BUGS.md: Documented SYNC-009 and MAIL-009 with full analysis
Unreleased - Hash Broadcast Improvements
Status: In Development Priority: MEDIUM
🔄 Hash Broadcasting Overhaul
Changes to /togbank share
- CHANGED: Now broadcasts hash for ONLY the current banker character (single alt)
- CHANGED: Uses togbank-hl channel for hash announcement (P2P discovery)
- CHANGED: No longer pushes full data - clients pull data via sync cycle
- IMPACT: Reduces spam when banker shares (1 hash vs 35+ data packets)
New Command: /togbank hashupdate
- NEW: Banker-only command to broadcast ALL bank alt hashes (the "nuke")
- USE CASE: Force guild-wide hash refresh after bulk inventory changes
- BEHAVIOR: Broadcasts hash-list for all bank alts on togbank-hl
- OUTPUT: "Broadcasted hash-list for N bank alts"
Hash Broadcast Enhancements
- ENHANCED:
BuildBankerHashList()now includesmailHashandmailUpdatedAt - ENHANCED: Hash-list-broadcast handler stores both inventory and mail hashes
- ENHANCED: Handler tracks what changed: "Updated AltName: inv: 123->456, mail: 789->999"
- FIXED: Non-bankers can now detect mail-only changes from hash broadcasts
- BEHAVIOR: No automatic requests triggered - users must run
/togbank syncor wait for automatic sync cycle
Technical Details
- Hash broadcasts contain:
inventoryHash,inventoryUpdatedAt,version,mailHash,mailUpdatedAt - Clients update local hash stubs when received
- Actual data requests happen during next sync cycle (manual, UI open, or 3-minute timer)
Files Changed:
Modules/Guild.lua:- Updated
BuildBankerHashList()to include mail hashes - Modified
Share()to broadcast single-alt hash on togbank-hl - Added
HashUpdate()function for all-alts hash broadcast
- Updated
Modules/Chat.lua:- Updated hash-list-broadcast handler to store both inventory and mail hashes
- Added
/togbank hashupdatecommand registration - Enhanced hash change detection and logging
[v0.8.9] (2026-02-07) - P2P Hash Backfill Complete
Status: Production Ready Priority: HIGH
🎯 P2P Hash Backfill Implementation
Core Features Implemented
- NEW: Banker HLR (hash list reply) stores authoritative hashes for all roster alts
- NEW: Version broadcasts store peer hashes when local hash is missing
- NEW: 3-minute rebroadcast timer requests hash list and rebroadcasts P2P for missing alts
- NEW: Roster sync fallback for officer-note-only guilds (config option, default OFF)
- FIXED: /wipe now rebuilds banker roster immediately (progress shows 0/35 instead of 0/2)
- FIXED: Data payloads always use GUILD channel (removed WHISPER routing for togbank-d3/d4)
- FIXED: SendWhisper now correctly treats AceComm nil return as success
- FIXED: Nil table access errors in Guild.lua (table initialization before access)
- FIXED: Inventory disappearing during async item loads - added loading indicator [UI-005]
- FIXED: Severe tooltip performance issues causing PC stuttering
- ENHANCED: P2P broadcasts happen for both "pending" (hash mismatch) and "missingContent" (hash match, no data)
📝 Technical Details
Hash Storage Priority System:
Primary: Banker HLR (togbank-hlr) - Most authoritative
- Banker has scanned all alts, provides definitive hash list
- Stores hash+updatedAt for all roster alts immediately
- Triggered on /sync, UI open, and every 3 minutes via timer
- Implementation: Chat.lua lines 1476-1510
Secondary: Peer Version Broadcasts (togbank-dv2) - Supplemental
- Fills gaps if HLR not received yet
- Only stores hash if we don't have one (hash=0 or nil)
- Implementation: Chat.lua lines 394-434
Result: After HLR, all 35 alts have authoritative hashes (pending=0)
Files Changed:
Modules/Chat.lua:- Added hash storage in HLR handler (two-pass: store hashes, then compare)
- Added hash storage in version broadcast handler (only if missing)
- Added debug logging for pending/missingContent broadcasts
Modules/Guild.lua:- Added
RebuildBankerRoster()call toReset()for immediate banker list after /wipe - Removed forceFull bypass logic (preserves P2P design)
- Changed
SendAltData()to always use GUILD channel for togbank-d3/d4
- Added
Modules/Events.lua:- Added
RequestHashListFromBanker()call toOnShareTimer()(3-minute rebroadcast)
- Added
Modules/DeltaComms.lua:- Updated
FastFillMissingAlts()to use P2P broadcasts when banker offline
- Updated
How It Works:
- On /sync or UI open: Request hash list from banker (togbank-hl)
- Banker replies: Send all alt hashes via togbank-hlr
- Store hashes: Create/update local alt stubs with banker's authoritative hash+updatedAt
- Compare: Categorize as "pending" (hash mismatch) or "missingContent" (hash match, no data)
- Broadcast: Send P2P requests to GUILD for missing alts with expectedHash
- Peers respond: Players with matching hash send data via GUILD
- Fallback: After 5s timeout, query banker directly via whisper
- Rebroadcast: Every 3 minutes, repeat steps 1-7 for still-missing alts
Design Principles:
- Banker is authoritative source for hash list
- P2P broadcasts reduce banker load
- GUILD channel for data, WHISPER for handshakes
- Newest-wins conflict resolution using inventoryUpdatedAt timestamps
[v0.8.4] (2026-02-02) - Mail Hash Synchronization Fix
Status: Critical Bug Fix Priority: HIGH
🐛 Critical Bug Fix
[MAIL-012] Mail Hash Never Set - Fixed Mail Synchronization
- FIXED:
mailHashfield was referenced but never assigned, breaking mail synchronization - ROOT CAUSE: Mail scan created mail data but never computed hash for change detection
- IMPACT: Mail items never synchronized between clients via
/togbank shareor/togbank sync - FIX:
Bank.luanow computesmailHashafter mail scan usingComputeInventoryHash()DeltaComms.luatracksmailHashchanges in delta computationDeltaComms.luaappliesmailHashchanges when receiving deltasDeltaComms.luarecognizesmailHashas a valid change type
- RESULT: Mail data now properly syncs between guild members
- LOGGING: Added
[MAIL-012]debug markers for mail hash operations
📝 Technical Details
Files Changed:
Modules/Bank.lua- Added mailHash computation after mail scan (lines 289-310)Modules/DeltaComms.lua- Track mailHash in ComputeDelta() (lines 533-545)Modules/DeltaComms.lua- Apply mailHash in ApplyDelta() (lines 806-810)Modules/DeltaComms.lua- Recognize mailHash in DeltaHasChanges() (lines 590-593)docs/DELTA_BUGS.md- Comprehensive bug documentation with root cause analysis
How It Works:
- When mail is scanned,
mailHashis computed fromalt.mail.items mailHashchanges trigger version updates in deltas- Receivers see
mailHashand know mail data is "new format" (not legacy) - Clients can detect mail changes and request updates
- Backward compatible: clients without
mailHashstill treated as "old format"
[v0.8.0] (2026-01-21) - Pull-Based Delta Protocol
Branch: feature/pull-based-delta Status: Testing Phase Latest Update: 2026-01-21 (Evening)
🚀 Major Features
Pull-Based Protocol with Inventory Hashing
- NEW: Hash-based inventory comparison replaces version timestamps
- NEW: Automatic pull sync when inventory hashes differ
- NEW: Dual broadcast system (
togbank-v+togbank-dv) for compatibility - NEW:
/togbank sharecommand broadcasts version data with hashes - NEW: Selective querying - only request data when hashes mismatch
- NEW: Data migration system computes hashes for existing alts on load
- NEW: Fast-fill feature - automatically requests missing banker alts when UI opens or
/togbank syncis used - NEW: Smart message prioritization - NORMAL priority for reliable delivery
- NEW: Communication debug filtering - Optional "(comm)" prefixed debug messages with separate toggle
Inventory Hashing System
ComputeInventoryHash()generates numeric hash from bank + bags + money- Hash computed automatically on bank scan (BANKFRAME_CLOSED event)
- Stored alongside version timestamp in
alt.inventoryHashfield - More reliable than version timestamps for detecting real changes
- Minimal overhead (single number vs full data comparison)
Protocol Simplification
- REMOVED: Guild support threshold requirement (was 5% minimum)
- NEW: Delta protocol always enabled if
PROTOCOL.SUPPORTS_DELTA = true - NEW: Works immediately without waiting for guild adoption
- SIMPLIFIED:
ShouldUseDelta()now only checks feature flags
Broadcast Enhancements
- Version Broadcast (
togbank-v): Legacy format with version timestamps only - Delta Version Broadcast (
togbank-dv): New format with version + hash - Format:
data.alts[name] = {version = X, hash = Y} - Share Command: Now sends BOTH broadcasts for maximum compatibility
Hash Comparison Logic
- Compares inventory hashes to detect changes
- We have no data: Query for everything
- Hashes differ: Query for update
- Hashes match: Skip query (no changes)
- No hash available: Fall back to version comparison
- Handles nil checks gracefully after database wipes
🐛 Bug Fixes
[SEARCH-003] Search Returning 0 Results
- Fixed: Search now correctly processes all aggregated items
- Root Cause: BuildSearchData was using
ipairs()on hash table returned byAggregate() - Solution: Changed to
pairs()for proper hash table iteration, fixed item counting - Impact: Search functionality now works correctly for all item queries
- Location: Search.lua lines 405-410
Mail Data Persistence
- Removed: Unused
IsMailDataStale()function and 1-hour staleness threshold - Change: Mail data now persists indefinitely like bank/bags data
- Impact: Mail inventory remains visible regardless of age, with timestamp displayed for information
- Location: MailInventory.lua
[UI-002] Item Links Not Appearing After Integration
- Fixed: Items now display immediately after async item link reconstruction
- Root Cause:
ReconstructItemLinks()was using asyncItem:ContinueOnItemLoad()callbacks without triggering UI refresh - Solution: Added UI refresh calls after successful link reconstruction (both immediate and async)
- Impact: Items now appear in UI as soon as their links become available from WoW API
- Location: Guild.lua lines 970-995
[PROTO-001] Delta Validation
- Fixed: Delta validation now accepts link-less deltas without
baseVersion - Made
baseVersionfield optional inValidateDeltaStructure() - Maintains backwards compatibility with old protocol deltas
- Location: Core.lua line 118-122
[UI-001] Inventory UI Crash
- Fixed: UI handles missing
bank.slotsandbags.slotsdata - Added defensive nil checks in Inventory.lua lines 177-187
- Data migration initializes missing slots fields with
{count = 0, total = 0} - Prevents crashes when opening UI with incomplete alt data
[DATA-001] Missing Inventory Hashes
- Fixed: Existing alt data migrated to include inventory hashes
- Migration runs once on addon load via
Database:InitializeDatabase() - Computes hashes from saved bank/bags/money data
- Successfully migrated 60+ existing alts in testing
Hash Comparison Edge Cases
- Fixed: Handles
nilhash values after database wipe - Fixed: Pull decision logic checks for missing data
- Fixed: Broadcasts send even when no alt data exists locally
- Debug output shows "has bank data for X (we have none), querying"
📝 Documentation Updates
- Updated DELTA_IMPLEMENTATION_TODO.md with current architecture
- Documented inventory hashing system and pull protocol flow
- Removed outdated guild support threshold documentation
- Added hash comparison algorithm documentation
- Updated bug tracker (DELTA_BUGS.md) with resolved issues
🔧 Technical Changes
- Guild.lua: Added dual broadcast to
Share()function - Guild.lua:
FastFillMissingAlts()auto-requests missing banker alts (lines 458-498) - Guild.lua:
ReconstructItemLinks()now refreshes UI after async link loading (lines 970-1008) - Events.lua:
SyncDeltaVersion()uses NORMAL priority for reliable delivery (was BULK) - Events.lua: Changed all query messages from BULK to NORMAL priority
- Chat.lua: Enhanced hash comparison logic with nil handling
- Chat.lua: Added UI auto-refresh when data adopted (togbank-d and togbank-d3 handlers)
- Chat.lua:
/togbank synccommand now also triggers fast-fill for missing alts - Database.lua: Added hash migration for existing alts
- Database.lua: Added slots migration to prevent UI crashes
- Core.lua: Made baseVersion optional in delta validation
- UI/Inventory.lua: Calls
FastFillMissingAlts()on Open() in delta mode (line 49) - Output.lua: Added
DebugComm()function for filterable communication debug logging - Options.lua: Added
commDebugtoggle in config UI below log level
🎯 Performance Improvements
- Message priority optimization: Changed queries and delta broadcasts from BULK to NORMAL
- Improved responsiveness of pull-based protocol handshake
- Faster UI updates with async item link reconstruction
- Reduced query spam with fast-fill on-demand loading
- Communication debug filtering: Separate toggle for comm debug messages with "(comm)" prefix
⚠️ Breaking Changes
None - Full backwards compatibility maintained with v0.7.0 clients
v0.7.0 (2025-01-17)
Latest Update: 2026-01-20 - Fixed error tracking issues
🐛 Bug Fixes (2026-01-20)
Error Tracking System
Fixed: Error tracking now works even when Guild.Info is not initialized
- Implemented temporary in-memory storage for errors occurring before guild initialization
- Automatic migration to database when guild data loads
- No error data loss during addon startup phase
- Query functions check both temporary and database storage
Fixed:
RecordDeltaError()logs debug messages when using temporary storage- Shows: "Using temporary error storage for <alt> (<type>): Guild.Info not initialized"
- Helps identify initialization timing issues
Fixed: Test function
testDeltaErrorTracking()parameter mismatch- Was calling
RecordDeltaError()with 2 parameters instead of required 3 - Now correctly passes:
altName,errorType,errorMessage - Ensures proper error categorization in test suite
- Was calling
Impact: Error tracking is now fully functional throughout addon lifecycle, including early delta failures before guild initialization completes.
🚀 Major Features
Delta Sync Protocol
- NEW: Intelligent delta synchronization protocol reduces bandwidth by 90-99%
- NEW: Automatic protocol version negotiation between v0.6.8 and v0.7.0+ clients
- NEW: Smart snapshot management with automatic corruption recovery
- NEW: Comprehensive error handling with automatic full sync fallback
- NEW: Backward compatible with v0.6.8 clients (seamless mixed-guild support)
Bandwidth Optimization
- Only transmits changed items instead of entire inventories
- Automatic size comparison (uses delta only if <30% of full sync size)
- Estimated bandwidth savings: 90-99% for typical inventory updates
- Guild-wide adoption threshold (50%) ensures efficient operation
Performance Metrics
- Real-time bandwidth tracking (delta vs full sync)
- Performance monitoring (computation and application times)
- Success rate tracking with automatic failure detection
- Estimated bandwidth savings calculations
✨ New Commands
/togbank deltastats- Display comprehensive delta sync statistics including:- Bandwidth usage breakdown (delta vs full syncs)
- Estimated total bandwidth saved
- Operation counts and success rates
- Average performance metrics (computation/application times)
/togbank deltaerrors- Show recent delta sync errors for debugging:- Last 10 errors with timestamps and error types
- Failure counts per alt
- Highlights alts with repeated failures (3+)
- Persists across /reload
/togbank deltahistory- Show stored delta chain history:- Delta storage per alt with version transitions
- Change types and ages for each delta
- Verifies chain replay infrastructure is working
/togbank protocol- Show protocol version distribution:- Online member protocol versions (v1 vs v2)
- All-time protocol adoption statistics
- Delta sync enablement status with threshold indicator
- Recently seen members with their protocol versions
/togbank clearsnapshots- Clear all delta snapshots (forces next sync to be full)/togbank forcefull- Toggle forcing full sync mode (temporarily disables delta sync)/togbank resetmetrics- Reset all delta sync statistics to zero
🔧 Technical Improvements
Database Layer
- Added
deltaSnapshotstable for efficient snapshot storage (1-hour expiration) - Added
guildProtocolVersionstable for peer protocol tracking - Added
deltaMetricstable for bandwidth and performance tracking - Implemented snapshot validation and automatic corruption recovery
- Added 23 new database functions for delta operations
Guild Module
- Rewrote
SendAltData()with intelligent protocol selection - Implemented
ComputeDelta()for efficient change detection - Implemented
ApplyDelta()with robust error handling - Added error tracking system with repeated failure detection
- Enhanced debug output with detailed size and timing information
Communication Layer
- Registered new
togbank-d2prefix for delta protocol - Enhanced version broadcast to include protocol capabilities
- Added delta structure validation before application
- Implemented automatic QueryAlt on all failure paths
Error Handling & Recovery
- 6 error detection points covering all failure scenarios
- Automatic full sync fallback on any delta failure
- Per-alt failure tracking with user notification (after 3 consecutive failures)
- Automatic failure count reset on successful sync
- Snapshot corruption detection and automatic purge
📊 Monitoring & Visibility
Enhanced Debug Output
- Delta selection logging with size comparisons and savings calculations
- Performance timing for all delta operations
- Color-coded status indicators (✓/✗) for quick visual parsing
- Detailed error messages with context for troubleshooting
Statistics Display
- Bandwidth metrics with color-coded percentages
- Success rate with threshold-based coloring (green ≥95%, yellow ≥80%, red <80%)
- Performance averages for computation and application
- Protocol adoption visualization
🧪 Testing & Quality
- Created comprehensive test module with 30+ unit tests
- Test coverage for delta computation, size estimation, protocol negotiation
- Error handling tests for all failure scenarios
- Integration tests for full delta roundtrip
- Backwards compatibility tests for v0.6.8 mixed guilds
📝 Documentation
- Added comprehensive README.txt with all commands and features
- Updated installation instructions with CurseForge App (recommended) method
- Added troubleshooting section specific to delta sync issues
- Created detailed DELTA_IMPLEMENTATION_TODO.md documenting all phases
- Added FEATURE_IMPROVEMENTS.md with technical architecture
🔄 Protocol Specifications
Version 2 Features
- Protocol version: 2
- Supports delta updates: Yes
- Delta size threshold: 30% of full sync
- Snapshot max age: 1 hour
- Guild adoption threshold: 50%
Backwards Compatibility
- v0.7.0+ ↔ v0.7.0+: Delta sync via
togbank-d2(when threshold met) - v0.7.0+ ↔ v0.6.8: Full sync via
togbank-d(automatic fallback) - v0.6.8 ↔ v0.6.8: Full sync via
togbank-d(unchanged) - No breaking changes - seamless upgrade path
🐛 Bug Fixes
- Fixed potential race conditions in snapshot management
- Improved error messages for version mismatch scenarios
- Enhanced validation to prevent corrupted delta application
- Added nil checks throughout delta codepaths
⚙️ Configuration
New constants in Modules/Constants.lua:
PROTOCOL = {
VERSION = 2,
SUPPORTS_DELTA = true,
MIN_DELTA_SIZE_RATIO = 0.3, -- 30% threshold
DELTA_SNAPSHOT_MAX_AGE = 3600, -- 1 hour
DELTA_SUPPORT_THRESHOLD = 0.5, -- 50% adoption
}
FEATURES = {
DELTA_ENABLED = true, -- Master enable/disable
FORCE_FULL_SYNC = false, -- Force full sync for testing
}
📈 Performance Impact
- Bandwidth Reduction: 90-99% for typical inventory updates
- Computation Overhead: ~2-3ms average per delta computation
- Application Overhead: ~1-2ms average per delta application
- Memory Impact: Minimal (~50KB per snapshot, auto-expiring)
🔮 Known Limitations
- Delta sync requires 50%+ of online guild to use v0.7.0+ for enablement
- Snapshots expire after 1 hour (forces full sync on first update after expiration)
- Large inventory changes (>30% of items) automatically fall back to full sync
- Options panel GUI for delta configuration deferred to future update
v2.3.0 (2025-10-27)
Full Changelog Previous Releases
- Merge pull request #3 from GrumpyPlayer/merge/fix-search-normalization-into-handle-malformed-data Merge/fix search normalization into handle malformed data
- fix issues related to clean-up and init, and also allow GM to author /bank roster updates
- Merge PR #1 (fix-search-normalization) into integration branch
- Perform cleanup of malformed data on addon initialization and handle malformed data better
- Fix nil version comparison in ReceiveAltData
- Added nil check for existing alt data version before comparison
- Prevents 'attempt to compare number with nil' error
- Fixes crash when receiving data for alts without version field
- Fix Search.lua crash and implement name normalization with security improvements
- Fixed nil table index crash in Search.lua duplicate detection
- Added NormalizePlayerName helper for consistent 'Name-Realm' format
- Implemented sender authentication to prevent communication spoofing
- Added debug tools: /bank debug toggle and /bank debugdump command
- Auto-enable bank reporting for detected bank characters
- Relaxed delegation policy for multi-bank account support
- Normalized player keys across all modules for data consistency

