Skip to content

Stored equipment on a cold cache, item level on Classic Era, and the guild broadcast - #11

Open
uga wants to merge 5 commits into
Thaoky:developmentfrom
uga:fix/equipment-and-guild-item-level
Open

Stored equipment on a cold cache, item level on Classic Era, and the guild broadcast#11
uga wants to merge 5 commits into
Thaoky:developmentfrom
uga:fix/equipment-and-guild-item-level

Conversation

@uga

@uga uga commented Aug 1, 2026

Copy link
Copy Markdown

Summary

Five fixes in DataStore_Inventory, around stored equipment and the guild item level broadcast. Verified in game on Classic Era and TBC Anniversary.


1. Do not wipe stored equipment when the item cache is cold

ScanInventorySlot() cleared a slot whenever GetInventoryItemLink() returned nil, without distinguishing an empty slot from an item whose link cannot be built yet because it is not in the client cache. On the first login after a patch this erased the character's whole stored inventory, which was then written to saved variables on logout, leaving the alt's grid column blank until the next login.

Falls back to GetInventoryItemID(), which reads local inventory data and stays valid while the cache is cold, and runs the delayed rescan on every version rather than retail only, so an unresolved link is picked up once the cache warms.

2. Compute the item level manually when the API returns zeroes

GetAverageItemLevel() does not exist on every version, and where it does it can still answer with zeroes on Classic Era. It is now only trusted when both values are usable, otherwise the manual calculation runs, instead of the character ending up with no item level at all.

3. Harden the guild item level broadcast against missing data

A nil item level would error out of format(), taking the whole broadcast with it, so one character without a usable value silenced the item level of every alt in the same message.

4 & 5. Answer for our own characters from our own data

A guild member may be one of our own characters: the one currently logged in, or an alt in the same guild. Those are now answered from our own data, which is always present and always fresher than anything the guild channel may have carried, and everyone else from the guild table.

The name is resolved through DataStore:GetCharacter() rather than asking GetNameOfMain() who the member belongs to: that one answers from the guild alts broadcast, so until that arrives it does not even recognise ourselves, and reading data we already have should not depend on the network.


Applicability

Fix Classic Era TBC Anniversary Notes
Equipment wipe on cold cache yes yes most visible right after a patch
Manual item level yes not needed GetAverageItemLevel() answers with zeroes on Classic Era; the change is version independent and simply falls through when the API is usable
Broadcast hardening yes yes
Own characters from own data yes yes

Note

The guild pane also needs the DataStore PR to show anything at all when the guild is homed on another realm of a connected group: the readers and the writers were resolving two different guild ids, and the guild-based dispatch returned early before these functions were ever called.


Related PRs

This is one change set spread over the repos it touches. Account sharing needs the first two together; the others are independent of each other.

Uga and others added 5 commits August 1, 2026 20:08
ScanInventorySlot() cleared a slot whenever GetInventoryItemLink() returned
nil, without distinguishing an empty slot from an item whose link cannot be
built yet because it is not in the client cache. On the first login after a
patch this erased the character's whole stored inventory, which then got
written to SavedVariables on logout, leaving the alt's grid column blank until
the next login.

Falls back to GetInventoryItemID(), which reads local inventory data and stays
valid while the cache is cold. Also runs the delayed rescan on every version,
not just retail, so an unresolved link is picked up once the cache warms up.
ScanAverageItemLevel() returned as soon as GetAverageItemLevel() existed,
whether or not it answered anything usable. On Classic Era the function is
there but returns zeroes, so the guard rejected the values, the early return
skipped the manual calculation, and averageItemLvl was never set at all - which
is why every AiL in the guild pane reads 0.0 while the same equipment shows up
fine under Grids.

The early return now happens only when the API actually produced an item level,
so an unusable answer falls through to the loop over the 18 equipped slots that
already exists for versions without the function.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GetAIL() passed the current character's item level straight to format("%d"),
which errors on nil - so a character without a stored item level did not just
broadcast a wrong value, it threw out of the login broadcast and no guild mate
received anything. The alt branch right below already guarded for this.

Three more nil paths on the same road, reachable now that item levels are
stored again: GetMemberKey() gave up when GetNameOfMain() returned nil, even
for our own character, where RequestGuildMemberEquipment() already falls back
to the member name; a member known only through his item level has no Inventory
table, which the slot lookup indexed blindly; and an equipment transfer for a
member never seen before indexed Members[character] before creating it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GetMemberKey() asked GetNameOfMain() who a guild member belongs to, and only
took the local path when the answer was our own name. GetNameOfMain() answers
from onlineMembers and the guild alts broadcast, so before that traffic arrives
it does not recognize even the character currently logged in. The lookup then
fell through to guild.Members[member], which holds nothing for a character that
never broadcast anything about itself, and the whole method returned no value -
which is what left the AiL column at 0.0 for the logged in character and for an
alt in the same guild, while the very same item level was correctly stored and
readable through GetAverageItemLevel().

The member name is now matched against our own characters on this realm and
account first, and only what does not resolve locally is looked up in the guild
table. Reading data we already have no longer depends on a broadcast having
arrived, and our own data wins over a possibly stale copy received earlier.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous attempt still resolved our characters by hand: it rebuilt the
character key from DataStore.ThisAccount and ThisRealm, asked GetCharacterID()
for an id, then indexed DataStore_Inventory_Characters directly. Three
assumptions, none of them verified from inside this file, and the AiL column
stayed at 0.0.

Both getters now go through the same public methods any other consumer uses:
DataStore:GetCharacter(name) to tell whether the member is one of ours, then
GetInventoryItem() / GetAverageItemLevel() on the returned key. Those are the
calls that are known to answer correctly for the logged in character, so the
guild pane now reads exactly what the rest of the addon reads. GetMemberKey()
is gone, replaced by a small helper that only looks up the guild table.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant