View Single Post
07/05/15, 02:36 PM   #1
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
[fixed] Custom guild rank names not well-defined -> game freezes

There's a long-standing bug -- related to custom guild rank names -- that causes the game to freeze whenever you select an "affected" guild in the Guild interface.

As of writing I'm aware of two affected guilds:
  • Twilight Market (EU)
  • Dark Brotherhood Merchant (??)
The bug only exhibits itself in English localization. Switching to German or French using /script SetCVar("language.2", "de" or "fr") allows you to view the guild interface without freezing. But it has nothing to do with non-ASCII characters, as one might guess at first.

Some time ago, I published an add-on/hack that prevents the freeze by replacing function ZO_GuildRanks_Shared:NeedsSave() with one that always returns false. This is okay for players who can't edit ranks, since we never need to save. I've been told the add-on "works" for officers as well, but obviously prevents them from changing ranks/permissions. So I was wondering why NeedsSave returns true during the very first refresh (before I had a chance to edit ranks), and despite the fact that I don't even have the required permission to edit ranks.

Twilight Market currently has four ranks (note there are only English letters):
  1. Guildmaster -- default (en)
  2. Officer -- default (en)
  3. Steward -- custom
  4. Trader -- custom

Strangely, rank.hasCustomName for the first two ranks is not always the same inside ZO_GuildRank_Shared:NeedsSave(). While clicking on different ranks in the guildRanks tab, their hasCustomName is sometimes true and sometimes false. I didn't try hard to find out why that happens, since I think the whole default/custom name logic needs more thought -- guilds are multi-lingual, yet GetDefaultGuildRankName() returns a localized string, not some canonical rank name.

What happens after ZO_GuildRanks_Shared:NeedsSave() returns true?
Lua Code:
  1. function ZO_GuildRanks_Keyboard:RefreshEditPermissions()
  2.     ...
  3.     else -- player doesn't have permission to edit permissions (ranks)
  4.         if(self:NeedsSave()) then
  5.             self:Cancel()
  6.         end
  7.     ...
  8. end
  9.  
  10. function ZO_GuildRanks_Keyboard:Cancel()
  11.     self:ClearSavePending()
  12.     self:RefreshRanksFromGuildData() -- !!!
  13. end

And here's the catch: RefreshRanksFromGuildData -> SelectRank -> RefreshRankInfo -> RefreshEditPermissions -> Cancel -> RefreshRanksFromGuildData -> BOOM

I'm going to rewrite my add-on so that instead of replacing NeedsSave(), it will prevent calling RefreshRanksFromGuildData() recursively. Of course, that doesn't fix the core issue with NeedsSave() returning true when it shouldn't.

For testing purposes I replaced global function DoesPlayerHaveGuildPermission() with one pretending that I do have GUILD_PERMISSION_PERMISSION_EDIT. Whenever I switch to Twilight Market's ranks tab, the Save and Cancel buttons immediately show up. In other guilds they only show up after I make changes. This means the core issue really lies in NeedsSave().