ZO_LEADERBOARD_PLAYER_DATA = 1 LEADERBOARD_DATA_TYPE = { -- these values are sorted in the order these leaderboards appear in the UIs. CAMPAIGN = 1, RAID = 2, ENDLESS_DUNGEON = 3, BATTLEGROUND = 4, TRIBUTE = 5, } ----------------- --Leaderboards Masterlist ----------------- ZO_LeaderboardsListManager_Shared = ZO_InitializingCallbackObject:Subclass() function ZO_LeaderboardsListManager_Shared:Initialize() self.masterList = {} self.pendingRequestData = {} EVENT_MANAGER:RegisterForEvent("LeaderboardsListManager", EVENT_RAID_LEADERBOARD_DATA_RECEIVED, function(_, ...) self:OnRaidLeaderboardDataReceived(...) end) EVENT_MANAGER:RegisterForEvent("LeaderboardsListManager", EVENT_BATTLEGROUND_LEADERBOARD_DATA_RECEIVED, function(_, ...) self:OnBattlegroundLeaderboardDataReceived(...) end) EVENT_MANAGER:RegisterForEvent("LeaderboardsListManager", EVENT_CAMPAIGN_LEADERBOARD_DATA_RECEIVED, function(_, ...) self:OnCampaignLeaderboardDataReceived(...) end) EVENT_MANAGER:RegisterForEvent("LeaderboardsListManager", EVENT_TRIBUTE_LEADERBOARD_DATA_RECEIVED, function(_, ...) self:OnTributeLeaderboardDataReceived(...) end) EVENT_MANAGER:RegisterForEvent("LeaderboardsListManager", EVENT_ENDLESS_DUNGEON_LEADERBOARD_DATA_RECEIVED, function(_, ...) self:OnEndlessDungeonLeaderboardDataReceived(...) end) end function ZO_LeaderboardsListManager_Shared:SetSelectedLeaderboard(data) self.subType = data.subType self.countFunction = data.countFunction self.maxAllowedRankFunction = data.maxRankFunction self.infoFunction = data.infoFunction self.pointsFormatFunction = data.pointsFormatFunction self.consoleIdRequestParamsFunction = data.consoleIdRequestParamsFunction self.playerInfoUpdateFunction = data.playerInfoUpdateFunction if self.leaderboardRankType ~= data.leaderboardRankType then self.leaderboardRankType = data.leaderboardRankType self:FireCallbacks("LeaderboardRankTypeChanged") end end function ZO_LeaderboardsListManager_Shared:BuildMasterList() ZO_ClearNumericallyIndexedTable(self.masterList) if not self.countFunction or not self.infoFunction then return end if self.playerInfoUpdateFunction then self.playerInfoUpdateFunction() end for i = 1, self.countFunction(self.subType) do local data = { index = i } self:SetupDataTable(data) self.masterList[#self.masterList + 1] = data end if self.maxAllowedRankFunction then self.maxAllowedRank = self.maxAllowedRankFunction() else self.maxAllowedRank = nil end end function ZO_LeaderboardsListManager_Shared:SetupDataTable(dataTable) if dataTable.index then local rank, playerDisplayName, characterName, points, class, alliance --Get and setup Leaderboard Type specific data if self.leaderboardRankType == LEADERBOARD_TYPE_ENDLESS_DUNGEON_OVERALL or self.leaderboardRankType == LEADERBOARD_TYPE_ENDLESS_DUNGEON_CLASS then local stage, cycle, arc rank, characterName, points, class, playerDisplayName, stage, cycle, arc = self.infoFunction(dataTable.index, self.subType) dataTable.stage = stage dataTable.cycle = cycle dataTable.arc = arc elseif self.leaderboardRankType == LEADERBOARD_TYPE_BATTLEGROUND or self.leaderboardRankType == LEADERBOARD_TYPE_TRIBUTE then rank, playerDisplayName, characterName, points = self.infoFunction(dataTable.index, self.subType) else rank, characterName, points, class, alliance, playerDisplayName = self.infoFunction(dataTable.index, self.subType) end --Setup common leaderboard data dataTable.characterName = characterName dataTable.displayName = playerDisplayName dataTable.type = ZO_GAMEPAD_INTERACTIVE_FILTER_LIST_SEARCH_TYPE_NAMES --This is the overall rank for the specific type of leaderboard you've requested. --The rank that is ultimately shown might be reshuffled based on the provided filters. dataTable.trueRank = rank dataTable.points = self.pointsFormatFunction and self.pointsFormatFunction(points) or points dataTable.class = class dataTable.alliance = alliance if alliance then dataTable.formattedAllianceName = ZO_CachedStrFormat(SI_ALLIANCE_NAME, GetAllianceName(alliance)) end end end function ZO_LeaderboardsListManager_Shared:FilterScrollList(list, filteredClass, preAddCallback, searchCallback) local scrollData = ZO_ScrollList_GetDataList(list) ZO_ClearNumericallyIndexedTable(scrollData) local maxAllowedRank = self.maxAllowedRank local lastTrueRank = 0 local currentRank = 0 local filteredIndex = 1 for _, data in ipairs(self:GetMasterList()) do if not filteredClass or data.class == filteredClass then --Re-rank based on class filtering if data.trueRank > lastTrueRank then lastTrueRank = data.trueRank currentRank = filteredIndex end --The list comes pre-sorted by rank, so all later entries don't matter if maxAllowedRank and currentRank > maxAllowedRank then break end data.rank = currentRank if not searchCallback or searchCallback(data) then if preAddCallback then preAddCallback(data) table.insert(scrollData, ZO_ScrollList_CreateDataEntry(ZO_LEADERBOARD_PLAYER_DATA, data)) end end filteredIndex = filteredIndex + 1 end end end function ZO_LeaderboardsListManager_Shared:GetConsoleIdRequestParams(index) return self.consoleIdRequestParamsFunction(index, self.subType) end function ZO_LeaderboardsListManager_Shared:GetMasterList() return self.masterList end function ZO_LeaderboardsListManager_Shared:QueryLeaderboardData(leaderboardType, queryData) self.pendingRequestType = leaderboardType self.pendingRequestData = queryData local readyState = LEADERBOARD_DATA_RESPONSE_PENDING if leaderboardType == LEADERBOARD_DATA_TYPE.BATTLEGROUND then readyState = QueryBattlegroundLeaderboardData(queryData.battlegroundType) if readyState == LEADERBOARD_DATA_READY then self:OnBattlegroundLeaderboardDataReceived(queryData.battlegroundType) end elseif leaderboardType == LEADERBOARD_DATA_TYPE.CAMPAIGN then readyState = QueryCampaignLeaderboardData(queryData.alliance) if readyState == LEADERBOARD_DATA_READY then self:OnCampaignLeaderboardDataReceived(queryData.campaignId, queryData.alliance) end elseif leaderboardType == LEADERBOARD_DATA_TYPE.RAID then readyState = QueryRaidLeaderboardData(queryData.raidCategory, queryData.raidId, queryData.classId) if readyState == LEADERBOARD_DATA_READY then self:OnRaidLeaderboardDataReceived(queryData.raidCategory, queryData.raidId, queryData.classId) end elseif leaderboardType == LEADERBOARD_DATA_TYPE.TRIBUTE then readyState = QueryTributeLeaderboardData(queryData.tributeType) if readyState == LEADERBOARD_DATA_READY then self:OnTributeLeaderboardDataReceived(queryData.tributeType) end elseif leaderboardType == LEADERBOARD_DATA_TYPE.ENDLESS_DUNGEON then readyState = QueryEndlessDungeonLeaderboardData(queryData.endlessDungeonGroupType, queryData.endlessDungeonId, queryData.classId) if readyState == LEADERBOARD_DATA_READY then self:OnEndlessDungeonLeaderboardDataReceived(queryData.endlessDungeonGroupType, queryData.endlessDungeonId, queryData.classId) end end if readyState == LEADERBOARD_DATA_RESPONSE_PENDING then self:SetLoadingState(true) end end function ZO_LeaderboardsListManager_Shared:OnRaidLeaderboardDataReceived(raidCategory, raidId, classId) if self.pendingRequestType ~= LEADERBOARD_DATA_TYPE.RAID then return end local passesCategoryCheck = self.pendingRequestData.raidCategory == raidCategory local passesIdCheck = self.pendingRequestData.raidId == raidId local passesClassCheck = raidCategory == RAID_CATEGORY_TRIAL or self.pendingRequestData.classId == classId if passesCategoryCheck and passesIdCheck and passesClassCheck then self:SetLoadingState(false) end end function ZO_LeaderboardsListManager_Shared:OnBattlegroundLeaderboardDataReceived(battlegroundType) if self.pendingRequestType ~= LEADERBOARD_DATA_TYPE.BATTLEGROUND then return end if self.pendingRequestData.battlegroundType == battlegroundType then self:SetLoadingState(false) end end function ZO_LeaderboardsListManager_Shared:OnCampaignLeaderboardDataReceived(campaignId, alliance) if self.pendingRequestType ~= LEADERBOARD_DATA_TYPE.CAMPAIGN then return end local passesAllianceCheck = self.pendingRequestData.alliance == alliance local passesCampaignCheck = self.pendingRequestData.campaignId == campaignId if passesAllianceCheck and passesCampaignCheck then self:SetLoadingState(false) end end function ZO_LeaderboardsListManager_Shared:OnTributeLeaderboardDataReceived(tributeType) if self.pendingRequestType ~= LEADERBOARD_DATA_TYPE.TRIBUTE then return end if self.pendingRequestData.tributeType == tributeType then self:SetLoadingState(false) end end function ZO_LeaderboardsListManager_Shared:OnEndlessDungeonLeaderboardDataReceived(groupType, endlessDungeonId, classId) if self.pendingRequestType ~= LEADERBOARD_DATA_TYPE.ENDLESS_DUNGEON then return end local passesGroupTypeCheck = self.pendingRequestData.endlessDungeonGroupType == groupType local passesIdCheck = self.pendingRequestData.endlessDungeonId == endlessDungeonId local passesClassCheck = groupType == ENDLESS_DUNGEON_GROUP_TYPE_DUO or self.pendingRequestData.classId == classId if passesGroupTypeCheck and passesIdCheck and passesClassCheck then self:SetLoadingState(false) end end function ZO_LeaderboardsListManager_Shared:SetLoadingState(isLoading) local leaderboard if IsInGamepadPreferredMode() then leaderboard = GAMEPAD_LEADERBOARDS else leaderboard = LEADERBOARDS end leaderboard:SetLoadingSpinnerVisibility(isLoading) if not isLoading then leaderboard:RefreshData() end end LEADERBOARD_LIST_MANAGER = ZO_LeaderboardsListManager_Shared:New() ----------------- --Leaderboards Shared ----------------- ZO_LeaderboardsManager_Shared = ZO_Object:Subclass() function ZO_LeaderboardsManager_Shared:New(control, leaderboardControl) leaderboardControl = leaderboardControl or control local manager = ZO_Object.New(self) manager:Initialize(control, leaderboardControl) return manager end function ZO_LeaderboardsManager_Shared:Initialize(control, leaderboardControl) self:InitializeScenes() self.leaderboardDataMetatable = {__index = function(dataTable, key) self:IndexFunction(dataTable, key) end} LEADERBOARD_LIST_MANAGER:RegisterCallback("LeaderboardRankTypeChanged", function() self:RepopulateFilterDropdown() end) LEADERBOARD_LIST_MANAGER:RegisterCallback("OnLeaderboardMasterListUpdated", function() if self.scene:IsShowing() then self:OnLeaderboardDataChanged(self.leaderboardObject) end end) self.leaderboardSystemObjects = {} end function ZO_LeaderboardsManager_Shared:RegisterLeaderboardSystemObject(systemObject, sortOrder) internalassert(self.leaderboardSystemObjects[sortOrder] == nil) self.leaderboardSystemObjects[sortOrder] = systemObject end function ZO_LeaderboardsManager_Shared:InitializeScenes(sceneName) self.scene = ZO_Scene:New(sceneName, SCENE_MANAGER) end function ZO_LeaderboardsManager_Shared:GetScene() return self.scene end function ZO_LeaderboardsManager_Shared:SetSelectedLeaderboardObject(leaderboardObject, subType) -- Should be overridden end function ZO_LeaderboardsManager_Shared:RefreshLeaderboardType(leaderboardType) -- Should be overridden end function ZO_LeaderboardsManager_Shared:RepopulateFilterDropdown() -- Should be overridden end function ZO_LeaderboardsManager_Shared:SetLoadingSpinnerVisibility(show) -- Should be overridden end function ZO_LeaderboardsManager_Shared:RefreshPointsHeader() -- Should be overridden end function ZO_LeaderboardsManager_Shared:GetLeaderboardTitleName(titleName, subType) return type(titleName) == "function" and titleName(subType) or titleName end function ZO_LeaderboardsManager_Shared:OnLeaderboardSelected(data) self:SetSelectedLeaderboardObject(data.leaderboardObject, data.subType) if self:GetScene():IsShowing() then LEADERBOARD_LIST_MANAGER:SetSelectedLeaderboard(data) data.leaderboardObject:SendLeaderboardQuery() end local titleName = self:GetLeaderboardTitleName(data.titleName, data.subType) self:SetActiveLeaderboardTitle(titleName) self:RefreshLeaderboardType(data.leaderboardRankType) self.headerPointsText = data.pointsHeaderString or GetString(SI_LEADERBOARDS_HEADER_POINTS) self:RefreshPointsHeader() end function ZO_LeaderboardsManager_Shared:OnLeaderboardDataChanged(leaderboardObject) if self.leaderboardObject == leaderboardObject then local data = self:GetSelectedLeaderboardData() if data then self:OnLeaderboardSelected(data) else self:RefreshData() end end end function ZO_LeaderboardsManager_Shared:SetupLeaderboardPlayerEntry(control, data) local leaderboardData = self:GetSelectedLeaderboardData() --Rank control.rankLabel:SetHidden(data.rank == 0) control.rankLabel:SetText(data.rank) --Name local safeDisplayName = data.displayName ~= "" and data.displayName or GetString(SI_LEADERBOARDS_STAT_NOT_AVAILABLE) local nameToUse = ZO_GetPlatformUserFacingName(data.characterName, safeDisplayName) control.nameLabel:SetText(nameToUse) --Class/Alliance/Progress local isEndlessDungeonLeaderboardType = leaderboardData.leaderboardRankType == LEADERBOARD_TYPE_ENDLESS_DUNGEON_OVERALL or leaderboardData.leaderboardRankType == LEADERBOARD_TYPE_ENDLESS_DUNGEON_CLASS local isBattlegroundLeaderboardType = leaderboardData.leaderboardRankType == LEADERBOARD_TYPE_BATTLEGROUND local isTributeLeaderboardType = self.leaderboardRankType == LEADERBOARD_TYPE_TRIBUTE local shouldShowClass = not isBattlegroundLeaderboardType and not isTributeLeaderboardType local shouldShowAlliance = not isEndlessDungeonLeaderboardType and not isBattlegroundLeaderboardType and not isTributeLeaderboardType if shouldShowClass then local classTexture = ZO_GetPlatformClassIcon(data.class) if(classTexture) then control.classIcon:SetHidden(false) control.classIcon:SetTexture(classTexture) else control.classIcon:SetHidden(true) end else control.classIcon:SetHidden(true) end if shouldShowAlliance then local allianceTexture = ZO_GetPlatformAllianceSymbolIcon(data.alliance) if(allianceTexture) then control.allianceIcon:SetHidden(false) control.allianceIcon:SetTexture(allianceTexture) else control.allianceIcon:SetHidden(true) end else control.allianceIcon:SetHidden(true) end if isEndlessDungeonLeaderboardType then control.progressLabel:SetHidden(false) local USE_THICK_OUTLINE = true local progressionString = ZO_EndlessDungeonManager.GetProgressionText(data.stage, data.cycle, data.arc, USE_THICK_OUTLINE) control.progressLabel:SetText(progressionString) else control.progressLabel:SetHidden(true) end --Points control.pointsLabel:SetText(data.points) --Background local bg = GetControl(control, "BG") if bg then local hidden = (data.index % 2) == 0 bg:SetHidden(hidden) end end function ZO_LeaderboardsManager_Shared:CommitScrollList() ZO_Scroll_ResetToTop(self.list) ZO_SortFilterList.CommitScrollList(self) end do local INCLUDE_ALL_FILTER = { [LEADERBOARD_TYPE_OVERALL] = true, [LEADERBOARD_TYPE_ALLIANCE] = true, [LEADERBOARD_TYPE_BATTLEGROUND] = true, [LEADERBOARD_TYPE_TRIBUTE] = true, [LEADERBOARD_TYPE_ENDLESS_DUNGEON_OVERALL] = true, } local INCLUDE_CLASS_FILTERS = { [LEADERBOARD_TYPE_OVERALL] = true, [LEADERBOARD_TYPE_ALLIANCE] = true, [LEADERBOARD_TYPE_CLASS] = true, [LEADERBOARD_TYPE_ENDLESS_DUNGEON_OVERALL] = true, [LEADERBOARD_TYPE_ENDLESS_DUNGEON_CLASS] = true, } function ZO_Leaderboards_PopulateDropdownFilter(dropdown, changedCallback, leaderboardType) dropdown:ClearItems() local defaultIndex = 1 local currentIndex = 0 local includeAllFilter = INCLUDE_ALL_FILTER[leaderboardType] if includeAllFilter then local entry = dropdown:CreateItemEntry(GetString(SI_LEADERBOARDS_FILTER_ALL_CLASSES), changedCallback) dropdown:AddItem(entry, ZO_COMBOBOX_SUPPRESS_UPDATE) currentIndex = currentIndex + 1 end if INCLUDE_CLASS_FILTERS[leaderboardType] then local desiredClass = not includeAllFilter and GetUnitClassId("player") for i = 1, GetNumClasses() do local classId = GetClassInfo(i) local className = zo_strformat(SI_CLASS_NAME, GetClassName(GENDER_MALE, classId)) local entry = dropdown:CreateItemEntry(className, changedCallback) entry.classId = classId dropdown:AddItem(entry, ZO_COMBOBOX_SUPPRESS_UPDATE) currentIndex = currentIndex + 1 if desiredClass and desiredClass == classId then defaultIndex = currentIndex end end end local IGNORE_CALLBACK = true dropdown:SelectItemByIndex(defaultIndex, IGNORE_CALLBACK) dropdown:GetContainer():SetHidden(currentIndex == 1) end end