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):
- Guildmaster -- default (en)
- Officer -- default (en)
- Steward -- custom
- 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:
function ZO_GuildRanks_Keyboard:RefreshEditPermissions()
...
else -- player doesn't have permission to edit permissions (ranks)
if(self:NeedsSave()) then
self:Cancel()
end
...
end
function ZO_GuildRanks_Keyboard:Cancel()
self:ClearSavePending()
self:RefreshRanksFromGuildData() -- !!!
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().