This is VERY TECHNICAL. The intended audience is not the support staff or end users. The intended audience is developers of addons and (possibly) Blizzard UI developers.
Starting in 8.1, progress in many achievements earned by alts count across all alts. This was already the case before, but now the system identifies these achievements both as completed (because done by alts) and tracks them as in-progress so that multiple alts can complete them.
This post is not for general audience. This is for addon developers, and if they are interested, for Blizzard developers.
This changes how GetAchievementCriteriaInfo() has to be called.
I do not work for Blizzard. I have tracked down AND FIXED this bug in some of the well-known addons. I have only fixed it on my local system. The bug is still happening BlizzardUI lua files on my system because, while I can change the 3rd party addons, I cannot change the Blizzard UI lua files.
The bug can potentially have consequences beyond just UI. If the client-side Blizzard scripts use GetAchievementCriteriaInfo during game play (and it’s called in a buggy way), it can cause unpredictable UI errors. Some of these errors may cause game-play issues if the errors are caught and ignored by the game client (instead of not happening).
Consider the following usage in Blizzard UI. You got credit for “Horde Slayer” achievement on an alt. You are in the process of completing this quest on the character you are using now. The game client gets an error (and ignores it in order to keep going). The situation-specific in-game loaded assets disappear. You were on a flying ship. It despawned. You died. Your “horde slayer” quest fails.
This would happen because while tracking your progress on this achievement, the client encountered a bug because your alt had the achievement.
Consider the following usage in (currently un-maintained) Altoholic UI. Actually, the bug is in the DataStore_Achievements addon (also unmaintained because it has the same author). The addon goes through the list of achievements and caches the ones it finds. It uses GetAchievementCriteriaInfo() to determine whether the current alt completed the achievement. It a lua “criteria not found” error without the work-around. Or it fails silently by following the work-around in the comments for Altoholic addon on curseforge.
The addons which I found to also be effected by these were BFAInvasionTimer.lua, Altoholic_Achievements/Templates/AchievementButton.lua, DataStore_Achievements/DataStore_Achievements.lua. But it also effects Blizzard UI when searching for and achievement and clicking on it if that achievement was completed by an alt. THIS DOESN’T HAPPEN TO ALL ACHIEVEMENTS. But when it does, it happens consistently. Removing all addons will not fix it because it happens in the internal Blizzard UI lua code as well.
The cause of this is that until 8.1, GetAchievementCriteriaInfo(achievementID, i) could be called for any achievement if the variable i was between 1 and the value returned by GetAchievementNumCriteria(achievementID). In 8.1 that’s no longer the case. If the achievement was completed by an alt, but the current character has incomplete progress on it, GetAchievementCriteriaInfo(achievementID, 1) can cause “criteria not found” error. However, GetAchievementCriteriaInfo(achievementID, 2) will return just fine.
The workaround that people suggested (in comments to altoholic addon) was to use GetAchievementCriteriaInfo(achievementID, 1, true). This will cause the function to return all nil’s instead of causing an error. However, this will put any addon or ui which uses it in an unpredictable state. Albeit, it will do so silently.
The actual fix is to recognize that it is now possible to have sparse criteria indexes and not always have criteria 1 through GetAchievementNumCriteria(achievementID).
In practice, this means that code such as below:
local num = GetAchievementNumCriteria(id)
for i = 1, num do
local criteriaStr, _, _, quantity = GetAchievementCriteriaInfo(id, i)
..... do something with "quantity" variable
end
has to be replaced with code like this:
local num = GetAchievementNumCriteria(id)
local iiiiii = 1
for i = 1, num do
local criteriaStr, quantity
while nil == criteriaStr do
criteriaStr, _, _, quantity = GetAchievementCriteriaInfo(id, iiiiii, true)
iiiiii = iiiiii + 1
end
..... do something with "quantity" variable
end
This will ensure that even if (for example) only criteria 2, 3, 8 are available for some achievement (and the rest of criteria are not), the code will pick out those criteria and ignore the rest.
Of course, this does assume that GetAchievementNumCriteria(id) continues to return the total number of available criteria for this achievement. This is currently the case, but if this part of the API is undergoing changes, this may need to be monitored closer by both the addon writers and possibly by the Blizzard UI developers.