class BattlePassController(IBattlePassController, EventsHandler): __itemsCache = dependency.descriptor(IItemsCache) __lobbyContext = dependency.descriptor(ILobbyContext) __offersProvider = dependency.descriptor(IOffersDataProvider) def __init__(self): self.__oldPoints = 0 self.__oldLevel = 0 self.__currentMode = None self.__eventsManager = EventManager() self.__seasonChangeNotifier = SimpleNotifier(self.__getTimeToNotifySeasonChanged, self.__onNotifySeasonChanged) self.__extraChapterNotifier = SimpleNotifier(self.__getTimeToExtraChapterExpired, self.__onNotifyExtraChapterExpired) self.onPointsUpdated = Event(self.__eventsManager) self.onLevelUp = Event(self.__eventsManager) self.onBattlePassIsBought = Event(self.__eventsManager) self.onSelectTokenUpdated = Event(self.__eventsManager) self.onSeasonStateChanged = Event(self.__eventsManager) self.onExtraChapterExpired = Event(self.__eventsManager) self.onBattlePassSettingsChange = Event(self.__eventsManager) self.onFinalRewardStateChange = Event(self.__eventsManager) self.onOffersUpdated = Event(self.__eventsManager) self.onRewardSelectChange = Event(self.__eventsManager) self.onChapterChanged = Event(self.__eventsManager) self.__rewardLogic = None return def init(self): super(BattlePassController, self).init() g_playerEvents.onClientUpdated += self.__onTokensUpdate self.__rewardLogic = BattlePassRewardLogic(BattlePassStateMachine()) BattlePassAwardsManager.init() def onLobbyInited(self, event): self._subscribe() self.__seasonChangeNotifier.startNotification() if any((self.isExtraChapter(chapterID) for chapterID in self.getChapterIDs())): self.__extraChapterNotifier.startNotification() self.__rewardLogic.start() self.onBattlePassSettingsChange(self.__getConfig().mode, self.__currentMode) self.__currentMode = self.__getConfig().mode def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() self.__clearFields() self.__rewardLogic.stop() def fini(self): self.__stop() self.__rewardLogic.stop() self.__clearFields() self.__eventsManager.clear() g_playerEvents.onClientUpdated -= self.__onTokensUpdate super(BattlePassController, self).fini() def isBought(self, chapterID, seasonID=None): def getTokens(season, chapter): return self.__itemsCache.items.tokens.getTokens().get(getBattlePassPassTokenName(season, chapter)) if seasonID is None: seasonID = self.getSeasonID() if chapterID is None: chapterID = self.getCurrentChapterID() if not chapterID: return False if not self.isExtraChapter(chapterID) and bool(getTokens(seasonID, 0)): return True else: token = getTokens(seasonID, chapterID) return token is not None def isOfferEnabled(self): return self.__lobbyContext.getServerSettings().isOffersEnabled() def isEnabled(self): return self.__getConfig().isEnabled() def isActive(self): return self.__getConfig().isActive(time_utils.getServerUTCTime()) def isVisible(self): return self.isSeasonStarted() and not self.isDisabled() and not self.isSeasonFinished() def isDisabled(self): return not self.isActive() and not self.isPaused() def isPaused(self): return self.__getConfig().isPaused() def isSeasonStarted(self): return self.__getConfig().seasonStart <= time_utils.getServerUTCTime() def isSeasonFinished(self): return self.__getConfig().seasonFinish <= time_utils.getServerUTCTime() def isValidBattleType(self, prbEntity): return prbEntity.getQueueType() in (QUEUE_TYPE.RANDOMS, QUEUE_TYPE.MAPBOX) def isGameModeEnabled(self, arenaBonusType): return self.__getConfig().isGameModeEnabled(arenaBonusType) def isCompleted(self): return self.getState() == BattlePassState.COMPLETED def getSupportedArenaBonusTypes(self): return [ arenaBonusType for arenaBonusType in self.__getConfig().points ] def getMaxLevelInChapter(self, chapterId=None): if chapterId is None: chapterId = first(self.getChapterIDs()) return self.__getConfig().getMaxChapterLevel(chapterId) def hasExtra(self): return any((self.isExtraChapter(chID) for chID in self.getChapterIDs())) def isRegularProgressionCompleted(self): chapterIDs = [] for chapterID in self.__getConfig().getChapterIDs(): if not self.isExtraChapter(chapterID): chapterIDs.append(chapterID) return all((self.getChapterState(chID) == ChapterState.COMPLETED for chID in chapterIDs)) def getExtraChapterID(self): return findFirst(self.isExtraChapter, self.getChapterIDs(), 0) def getRewardType(self, chapterID): return self.__getConfig().getRewardType(chapterID) def isChapterExists(self, chapterID): return chapterID in self.getChapterIDs() def getChapterIDs(self): def isActive(chID): expireTimestamp = self.__getConfig().getChapterExpireTimestamp(chID) return not expireTimestamp or time_utils.getServerUTCTime() < expireTimestamp return [ chapterID for chapterID in self.__getConfig().getChapterIDs() if isActive(chapterID) ] def isExtraChapter(self, chapterID): return self.__getConfig().isExtraChapter(chapterID) def getBattlePassCost(self, chapterID): return Money(**self.__getConfig().getbattlePassCost(chapterID)) def getChapterExpiration(self, chapterID): return self.__getConfig().getChapterExpireTimestamp(chapterID) if self.isExtraChapter(chapterID) else 0 def getChapterRemainingTime(self, chapterID): remainingTime = 0 if self.isExtraChapter(chapterID): remainingTime = max(0, self.getChapterExpiration(chapterID) - time_utils.getServerUTCTime()) return remainingTime def isRareLevel(self, chapterID, level): realLevel = min(level, self.getMaxLevelInChapter(chapterID)) tags = self.__getConfig().getTags(chapterID, realLevel, BattlePassConsts.REWARD_PAID) return BattlePassConsts.RARE_REWARD_TAG in tags def isFinalLevel(self, chapterID, level): return level >= self.getMaxLevelInChapter(chapterID) def getRewardLogic(self): return self.__rewardLogic def getSingleAward(self, chapterId, level, awardType=BattlePassConsts.REWARD_FREE, needSort=True): reward = {} if awardType in (BattlePassConsts.REWARD_FREE, BattlePassConsts.REWARD_PAID): reward = self.__getConfig().getRewardByType(chapterId, level, awardType) elif awardType == BattlePassConsts.REWARD_BOTH: rewards = [self.__getConfig().getFreeReward(chapterId, level), self.__getConfig().getPaidReward(chapterId, level)] return BattlePassAwardsManager.hideInvisible(BattlePassAwardsManager.composeBonuses(rewards)) if needSort: rewards = BattlePassAwardsManager.composeBonuses([reward]) else: rewards = awardsFactory(reward) return BattlePassAwardsManager.hideInvisible(rewards, needSplit=not needSort) def getAwardsInterval(self, chapterId, fromLevel, toLevel, awardType=BattlePassConsts.REWARD_FREE): result = {} for level in range(fromLevel, toLevel + 1): result[level] = self.getSingleAward(chapterId, level, awardType, True) return result def getPackedAwardsInterval(self, chapterId, fromLevel, toLevel, awardType=BattlePassConsts.REWARD_FREE): result = [] for level in range(fromLevel, toLevel + 1): result.extend(self.getSingleAward(chapterId, level, awardType, False)) return BattlePassAwardsManager.sortBonuses(result) def isNeedToTakeReward(self, chapterId, awardType, level): bonuses = self.getSingleAward(chapterId, level, awardType) if level > self.getLevelInChapter(chapterId): return False else: for bonus in bonuses: if bonus.getName() == BATTLE_PASS_SELECT_BONUS_NAME: for tokenID in bonus.getTokens().iterkeys(): if self.__itemsCache.items.tokens.getToken(tokenID) is not None: return True return False def replaceOfferByReward(self, bonuses): result = [] for bonus in bonuses: if bonus.getName() == BATTLE_PASS_SELECT_BONUS_NAME: bonus.updateContext({'isReceived': False}) hasGift = False for tokenID in bonus.getTokens().iterkeys(): offerToken = getOfferTokenByGift(tokenID) offer = self.__offersProvider.getOfferByToken(offerToken) if offer is not None: receivedGifts = self.__offersProvider.getReceivedGifts(offer.id) if receivedGifts: for giftId, count in receivedGifts.iteritems(): if count > 0: gift = offer.getGift(giftId) if gift is not None: hasGift = True result.extend(gift.bonuses) if not hasGift: result.append(bonus) result.append(bonus) return result def isChooseRewardEnabled(self, awardType, chapterId, level): if level > self.getLevelInChapter(chapterId): return False else: bonuses = self.getSingleAward(chapterId, level, awardType) for bonus in bonuses: if bonus.getName() == BATTLE_PASS_SELECT_BONUS_NAME: for tokenID in bonus.getTokens().iterkeys(): if self.__itemsCache.items.tokens.getToken(tokenID) is not None: return self.isOfferEnabled() and self.__offersProvider.getOfferByToken(getOfferTokenByGift(tokenID)) is not None return False def canChooseAnyReward(self): return self.isOfferEnabled() and any((token.startswith(BATTLE_PASS_CHOICE_REWARD_OFFER_GIFT_TOKENS) for token in self.__itemsCache.items.tokens.getTokens().iterkeys() if self.__offersProvider.getOfferByToken(getOfferTokenByGift(token)) is not None)) def getChapterIndex(self, chapterID): sortedChapterIDs = sorted(self.getChapterIDs()) return sortedChapterIDs.index(chapterID) def getLevelsConfig(self, chapterID): return self.__getConfig().getChapterLevels(chapterID) def getPointsInChapter(self, chapterID): return self.__itemsCache.items.battlePass.getPointsByChapterID(chapterID) def getLevelInChapter(self, chapterID): return self.__itemsCache.items.battlePass.getCurrentLevelByChapterID(chapterID) def getCurrentLevel(self): return self.getLevelInChapter(self.getCurrentChapterID()) def getCurrentChapterID(self): activeChapter = self.__itemsCache.items.battlePass.getActiveChapterID() if activeChapter not in self.getChapterIDs(): activeChapter = 0 return activeChapter def hasActiveChapter(self): return bool(self.getCurrentChapterID()) @process def activateChapter(self, chapterID, seasonID=None): yield BattlePassActivateChapterProcessor(chapterID, seasonID or self.getSeasonID()).request() def getFreePoints(self): return self.__itemsCache.items.battlePass.getNonChapterPoints() def getState(self): return self.__itemsCache.items.battlePass.getState() def getPrevSeasonsStats(self): packedStats = self.__itemsCache.items.battlePass.getPackedStats() if not packedStats: return None else: unpackStats, _ = BattlePassStatsCommon.unpackAllSeasonStats(packedStats) return unpackStats def getLastFinishedSeasonStats(self): allSeasonStats = self.getPrevSeasonsStats() if not allSeasonStats: seasons = sorted(self.getSeasonsHistory().keys(), reverse=True) return BattlePassStatsCommon.makeSeasonStats(first(seasons), {}, BattlePassStatsCommon.initialSeasonStatsData()) return allSeasonStats[-1] def getSeasonsHistory(self): return {} def getLevelPoints(self, chapterID, level): levelsConfig = self.getLevelsConfig(chapterID) return levelsConfig[0] if level <= 0 else levelsConfig[level] - levelsConfig[level - 1] def getChapterState(self, chapterID): if self.getLevelInChapter(chapterID) >= self.getMaxLevelInChapter(chapterID): state = ChapterState.COMPLETED elif self.getCurrentChapterID() is not None and self.getCurrentChapterID() == chapterID: state = ChapterState.ACTIVE elif chapterID in self.__itemsCache.items.battlePass.getChapterStats(): state = ChapterState.PAUSED else: state = ChapterState.NOT_STARTED return state def isChapterActive(self, chapterID): return self.getChapterState(chapterID) == ChapterState.ACTIVE def isChapterCompleted(self, chapterID): return self.getChapterState(chapterID) == ChapterState.COMPLETED def getFullChapterPoints(self, chapterID): levelsConfig = self.getLevelsConfig(chapterID) _, maxLevel = self.getChapterLevelInterval(chapterID) return levelsConfig[maxLevel - 1] def getLevelProgression(self, chapterID): if self.isDisabled(): return (0, 0) if not chapterID: return (0, 0) level = self.getLevelInChapter(chapterID) points = self.getPointsInChapter(chapterID) return self.getProgressionByPoints(chapterID, points, level) def getLevelByPoints(self, chapterID, points): return self.getMaxLevelInChapter(chapterID) if points >= self.getLevelsConfig(chapterID)[-1] else bisect.bisect_right(self.getLevelsConfig(chapterID), points) def getProgressionByPoints(self, chapterID, points, level): levelsConfig = self.getLevelsConfig(chapterID) if level >= self.getMaxLevelInChapter(chapterID): points = levelsConfig[-1] - levelsConfig[-2] return (points, points) if level <= 0: basePoints = 0 limitPoints = levelsConfig[0] else: basePoints = levelsConfig[level - 1] limitPoints = levelsConfig[level] - basePoints levelPoints = points - basePoints return (levelPoints, limitPoints) def getPerBattlePoints(self, gameMode=ARENA_BONUS_TYPE.REGULAR, vehCompDesc=None): winList = self.__getPackedBonusPointsList(vehTypeCompDescr=vehCompDesc, gameMode=gameMode) lostList = self.__getPackedBonusPointsList(vehTypeCompDescr=vehCompDesc, isWinner=False, gameMode=gameMode) count = 0 result = [] for winInfo, lostInfo in zip(winList, lostList): pointsWin, pointsCount = winInfo pointsLost, _ = lostInfo count += pointsCount if pointsWin > 0: item = TopPoints(count, pointsWin, pointsLost) result.append(item) return result def getPerBattleRoyalePoints(self, gameMode=ARENA_BONUS_TYPE.BATTLE_ROYALE_SOLO, vehCompDesc=None): winList = self.__getConfig().bonusPointsList(vehCompDesc, isWinner=True, gameMode=gameMode) pointsList = list(self.__getConfig().bonusPointsList(vehCompDesc, isWinner=False, gameMode=gameMode)) pointsList[0] = winList[0] pointList = [ (key, len(list(group))) for key, group in groupby(pointsList) ] count = 0 result = [] if not winList or not pointList: _logger.error('Failed to get bonus points information! Check server settings are correct for Battle Royale.') return result for item in pointList: points, pointsCount = item count += pointsCount if points > 0: result.append(BattleRoyaleTopPoints(count, points)) return result def getChapterConfig(self): return [ self.getMaxLevelInChapter(chapter) for chapter in self.getChapterIDs() ] def getChapterLevelInterval(self, chapterID): return self.__getConfig().getChapterBorders(chapterID) def isSpecialVehicle(self, intCD): return self.__getConfig().isSpecialVehicle(intCD) def getSpecialVehicles(self): return self.__getConfig().getSpecialVehicles() def getPointsDiffForVehicle(self, intCD, gameMode=ARENA_BONUS_TYPE.REGULAR): defaultWinList = self.__getPackedBonusPointsList(gameMode=gameMode) diffWinList = self.__getPackedBonusPointsList(vehTypeCompDescr=intCD, isDiff=True, gameMode=gameMode) if not defaultWinList or not diffWinList: _logger.error('Failed to get bonus points information! Check server settings are correct.') return PointsDifference(0, 0, 0) diffBlock = diffWinList[0] bonus = diffBlock[0] top = diffBlock[1] textID = getPointsInfoStringID() return PointsDifference(bonus, top, textID) def getVehicleProgression(self, intCD): points = self.__itemsCache.items.battlePass.getPointsForVehicle(intCD, 0) cap = self.__getConfig().vehicleCapacity(intCD) return (points, cap) def getSpecialVehicleCapBonus(self): return self.__getConfig().vehicleCapacity(first(self.getSpecialVehicles())) def getVehicleCapBonus(self, intCD): vehicle = self.__itemsCache.items.getItemByCD(intCD) return 0 if vehicle is None else self.__getConfig().capBonus(vehicle.level) def getSeasonTimeLeft(self): return max(0, self.getSeasonFinishTime() - time_utils.getServerUTCTime()) def getFinalOfferTimeLeft(self): return max(0, self.getFinalOfferTime() - time_utils.getServerUTCTime()) def getSeasonStartTime(self): return self.__getConfig().seasonStart def getSeasonFinishTime(self): return self.__getConfig().seasonFinish def hasMaxPointsOnVehicle(self, intCD): currentPoints, limitPoints = self.getVehicleProgression(intCD) return currentPoints >= limitPoints > 0 def isProgressionOnVehiclePossible(self, intCD): return self.__getConfig().vehicleCapacity(intCD) > 0 def getSeasonID(self): return self.__itemsCache.items.battlePass.getSeasonID() def getSeasonNum(self): return self.__getConfig().seasonNum def getFinalOfferTime(self): return self.__getConfig().finalOfferTime def getStylesConfig(self): return {chapterID:chapterInfo.get('styleId') for chapterID, chapterInfo in self.__getConfig().chapters.iteritems()} def getNotChosenRewardCount(self): return sum((token.startswith(BATTLE_PASS_CHOICE_REWARD_OFFER_GIFT_TOKENS) for token in self.__itemsCache.items.tokens.getTokens().iterkeys() if self.__offersProvider.getOfferByToken(getOfferTokenByGift(token)) is not None)) def hasAnyOfferGiftToken(self): return any((token.startswith(BATTLE_PASS_CHOICE_REWARD_OFFER_GIFT_TOKENS) for token in self.__itemsCache.items.tokens.getTokens().iterkeys())) def takeRewardForLevel(self, chapterID, level): isBought = self.isBought(chapterID=chapterID) awardType = BattlePassConsts.REWARD_BOTH if isBought else BattlePassConsts.REWARD_FREE isOfferEnabled = self.isOfferEnabled() bonuses = self.getSingleAward(chapterID, level, awardType) rewardsToChoose = [] stylesToChoose = [] for bonus in bonuses: bonusName = bonus.getName() if bonusName == BATTLE_PASS_SELECT_BONUS_NAME and isOfferEnabled: for tokenID in bonus.getTokens().iterkeys(): if self.__itemsCache.items.tokens.getToken(tokenID) is not None and self.__offersProvider.getOfferByToken(getOfferTokenByGift(tokenID)) is not None: rewardsToChoose.append(tokenID) if bonusName == BATTLE_PASS_STYLE_PROGRESS_BONUS_NAME: for tokenID in bonus.getTokens().iterkeys(): if self.__itemsCache.items.tokens.getToken(tokenID) is not None: chapter = bonus.getChapter() if chapter not in stylesToChoose: stylesToChoose.append(chapter) rewardsToChoose.sort(key=lambda x: (int(x.split(':')[-1]), x.split(':')[-2])) self.getRewardLogic().startManualFlow(rewardsToChoose, chapterID, level) return def takeAllRewards(self): if self.isOfferEnabled(): rewardsToChoose = [ token for token in self.__itemsCache.items.tokens.getTokens().iterkeys() if token.startswith(BATTLE_PASS_CHOICE_REWARD_OFFER_GIFT_TOKENS) and self.__offersProvider.getOfferByToken(getOfferTokenByGift(token)) is not None ] rewardsToChoose.sort(key=lambda x: (int(x.split(':')[-1]), x.split(':')[-2])) else: rewardsToChoose = [] self.getRewardLogic().startManualFlow(rewardsToChoose, 0) return def getChapterStyleProgress(self, chapter): return getMaxAvalable3DStyleProgressInChapter(self.getSeasonID(), chapter, self.__itemsCache.items.tokens.getTokens().keys()) def _getEvents(self): return ((self.__lobbyContext.getServerSettings().onServerSettingsChange, self.__onConfigChanged), (self.__lobbyContext.getServerSettings().onServerSettingsChange, self.__onOffersStateChanged), (self.__itemsCache.onSyncCompleted, self.__onSyncCompleted), (self.__offersProvider.onOffersUpdated, self.__onOffersUpdated)) def __stop(self): self.__seasonChangeNotifier.stopNotification() self.__extraChapterNotifier.stopNotification() self._unsubscribe() def __getConfig(self): return self.__lobbyContext.getServerSettings().getBattlePassConfig() def __onTokensUpdate(self, diff, _): tokens = diff.get('tokens', {}) if not tokens: return for chapter in self.getChapterIDs(): if getBattlePassPassTokenName(self.getSeasonID(), chapter) in tokens: self.onBattlePassIsBought() break if any((tokenID.startswith(BATTLE_PASS_OFFER_TOKEN_PREFIX) for tokenID, token in tokens.iteritems())): self.onSelectTokenUpdated() def __getTimeUntilStart(self): return max(0, self.__getConfig().seasonStart - time_utils.getServerUTCTime()) def __getTimeToNotifySeasonChanged(self): if not self.isPaused(): if not self.isSeasonStarted(): return self.__getTimeUntilStart() if not self.isSeasonFinished(): return self.getSeasonTimeLeft() def __getTimeToExtraChapterExpired(self): extraChapterID = findFirst(self.isExtraChapter, self.getChapterIDs(), 0) return max(0, self.getChapterExpiration(extraChapterID) - time_utils.getServerUTCTime()) def __onNotifySeasonChanged(self): self.onSeasonStateChanged() def __onNotifyExtraChapterExpired(self): self.onExtraChapterExpired() @serverSettingsChangeListener(BATTLE_PASS_CONFIG_NAME) def __onConfigChanged(self, diff): config = diff[BATTLE_PASS_CONFIG_NAME] self.__seasonChangeNotifier.startNotification() chapters = config.get('season', {}).get('chapters', {}) if any((self.isExtraChapter(chapterID) for chapterID in chapters)): self.__extraChapterNotifier.stopNotification() self.__extraChapterNotifier = SimpleNotifier(self.__getTimeToExtraChapterExpired, self.__onNotifyExtraChapterExpired) self.__extraChapterNotifier.startNotification() else: self.__extraChapterNotifier.stopNotification() newMode = None oldMode = self.__currentMode if 'mode' in config: newMode = config['mode'] self.__currentMode = newMode self.onBattlePassSettingsChange(newMode, oldMode) return @serverSettingsChangeListener(OFFERS_ENABLED_KEY) def __onOffersStateChanged(self, diff): self.__onOffersUpdated() def __onSyncCompleted(self, _, diff): if BATTLE_PASS_PDATA_KEY not in diff: return data = diff[BATTLE_PASS_PDATA_KEY] newPoints = data.get('sumPoints', self.__oldPoints) newLevel = data.get('level', self.__oldLevel) if newPoints != self.__oldPoints: self.onPointsUpdated() if newLevel != self.__oldLevel: self.onLevelUp() self.__oldPoints = newPoints self.__oldLevel = newLevel if 'chapterID' in data: self.onChapterChanged() def __onOffersUpdated(self): self.__validateOffers() self.onOffersUpdated() def __validateOffers(self): for offer in self.__offersProvider.iAvailableOffers(False): if not offer.token.startswith(BATTLE_PASS_OFFER_TOKEN_PREFIX): continue counts = {gift.giftCount for gift in offer.getAllGifts()} if len(counts) > 1: _logger.error('Wrong bonus count in gifts. Offer token %s', offer.token) @staticmethod def __bonusPointsDiffList(vehTypeCompDescr, config, gameMode): defaultPoints = config.points.get(gameMode, {}) defaultDiff = [0] * len(defaultPoints.get('win', [])) if vehTypeCompDescr in defaultPoints and 'win' in defaultPoints: specialPoints = defaultPoints[vehTypeCompDescr] defaultPoints = defaultPoints['win'] specialPoints = specialPoints['win'] return [ a - b for a, b in zip(specialPoints, defaultPoints) ] return defaultDiff def __getPackedBonusPointsList(self, vehTypeCompDescr=None, isWinner=True, isDiff=False, gameMode=ARENA_BONUS_TYPE.REGULAR): if isDiff: pointsList = self.__bonusPointsDiffList(vehTypeCompDescr, self.__getConfig(), gameMode) else: pointsList = self.__getConfig().bonusPointsList(vehTypeCompDescr, isWinner, gameMode) return [ (key, len(list(group))) for key, group in groupby(pointsList) ] @staticmethod def __checkIfRewardIsToken(bonusName, reward): if 'tokens' not in reward: return False bonuses = BattlePassAwardsManager.composeBonuses([reward]) for bonus in bonuses: if bonus.getName() == bonusName: return True return False def __clearFields(self): self.__oldPoints = 0 self.__oldLevel = 0 self.__currentMode = None return
class EpicBattleMetaGameController(Notifiable, SeasonProvider, IEpicBattleMetaGameController, IGlobalListener): bootcampController = dependency.descriptor(IBootcampController) __itemsCache = dependency.descriptor(IItemsCache) __eventsCache = dependency.descriptor(IEventsCache) __settingsCore = dependency.descriptor(ISettingsCore) __lobbyContext = dependency.descriptor(ILobbyContext) __battleResultsService = dependency.descriptor(IBattleResultsService) __offersProvider = dependency.descriptor(IOffersDataProvider) MAX_STORED_ARENAS_RESULTS = 20 DAILY_QUEST_ID = 'front_line' FINAL_BADGE_QUEST_ID = 'epicmetagame:progression_finish' def __init__(self): super(EpicBattleMetaGameController, self).__init__() self.onUpdated = Event.Event() self.onPrimeTimeStatusUpdated = Event.Event() self.onEventEnded = Event.Event() self.onGameModeStatusTick = Event.Event() self.__skillData = {} self.__playerMaxLevel = 0 self.__levelProgress = tuple() self.__abilityPointsForLevel = list() self.__performanceGroup = None self.__isEpicSoundMode = False self.__rankSettings = {} self.__showedResultsForArenas = [] self.__eventEndedNotifier = None self.__urlMacros = None return def init(self): super(EpicBattleMetaGameController, self).init() self.__urlMacros = URLMacros() self.addNotificator(SimpleNotifier(self.getTimer, self.__timerUpdate)) self.addNotificator(PeriodicNotifier(self.getTimer, self.__timerTick)) self.__eventEndedNotifier = SimpleNotifier(self.getEventTimeLeft, self.__onEventEnded) self.addNotificator(self.__eventEndedNotifier) def fini(self): del self.__showedResultsForArenas[:] self.onUpdated.clear() self.onPrimeTimeStatusUpdated.clear() self.onGameModeStatusTick.clear() self.onEventEnded.clear() self.clearNotification() self.stopGlobalListening() self.__urlMacros = None super(EpicBattleMetaGameController, self).fini() return def onLobbyInited(self, ctx): self.__lobbyContext.getServerSettings( ).onServerSettingsChange += self.__updateEpicMetaGameSettings g_currentVehicle.onChanged += self.__invalidateBattleAbilities self.__itemsCache.onSyncCompleted += self.__invalidateBattleAbilities g_clientUpdateManager.addCallbacks({ 'epicMetaGame': self.__updateEpic, 'inventory': self.__onInventoryUpdate, 'tokens': self.__onTokensUpdate }) self.startGlobalListening() self.__setData() self.__invalidateBattleAbilities() self.startNotification() if self.getPerformanceGroup() == EPIC_PERF_GROUP.HIGH_RISK: self.__lobbyContext.addFightButtonConfirmator( self.__confirmFightButtonPressEnabled) self.__isEpicSoundMode = False if self.prbEntity is not None: enableSound = bool(self.prbEntity.getModeFlags() & FUNCTIONAL_FLAG.EPIC) self.__updateSounds(enableSound) return def onDisconnected(self): self.__clear() def onPrbEntitySwitching(self): if self.prbEntity is None: return else: switchedFromEpic = bool(self.prbEntity.getModeFlags() & FUNCTIONAL_FLAG.EPIC) if switchedFromEpic: self.__updateSounds(False) return def onPrbEntitySwitched(self): self.__invalidateBattleAbilities() if self.prbEntity is None: return else: isEpicSoundMode = bool(self.prbEntity.getModeFlags() & FUNCTIONAL_FLAG.EPIC) if isEpicSoundMode: self.__updateSounds(True) return def onAccountBecomePlayer(self): self.__battleResultsService.onResultPosted += self.__showBattleResults def onAvatarBecomePlayer(self): self.__clear() self.__battleResultsService.onResultPosted -= self.__showBattleResults def getModeSettings(self): return self.__lobbyContext.getServerSettings().epicBattles def isEnabled(self): return self.getModeSettings().isEnabled def isEpicPrbActive(self): return False if self.prbEntity is None else bool( self.prbEntity.getModeFlags() & FUNCTIONAL_FLAG.EPIC) def isCurrentCycleActive(self): season = self.getCurrentSeason() return season.hasActiveCycle(time_utils.getCurrentLocalServerTimestamp( )) if season is not None else False def isUnlockVehiclesInBattleEnabled(self): return any(self.getUnlockableInBattleVehLevels()) def isDailyQuestsUnlocked(self): currrentLevel, _ = self.getPlayerLevelInfo() return currrentLevel >= self.getMaxPlayerLevel() def isDailyQuestsRefreshAvailable(self): if self.hasPrimeTimesLeftForCurrentCycle(): return True primeTimePeriodsForDay = self.getPrimeTimesForDay( time_utils.getCurrentLocalServerTimestamp()) if primeTimePeriodsForDay: _, periodTimeEnd = max(primeTimePeriodsForDay.values(), key=itemgetter(1)) periodTimeLeft = periodTimeEnd - time_utils.getCurrentLocalServerTimestamp( ) return periodTimeLeft > time_utils.getDayTimeLeft() return False def getPerformanceGroup(self): if not self.__performanceGroup: self.__analyzeClientSystem() _logger.debug('Current performance group %s', self.__performanceGroup) return self.__performanceGroup def getMaxPlayerLevel(self): return self.__playerMaxLevel def getStageLimit(self): return self.__stageLimit def getAbilityPointsForLevel(self): return self.__abilityPointsForLevel def getValidVehicleLevels(self): return self.getModeSettings().validVehicleLevels def getUnlockableInBattleVehLevels(self): return self.getModeSettings().unlockableInBattleVehLevels def getSuitableForQueueVehicleLevels(self): return set(self.getValidVehicleLevels()) - set( self.getUnlockableInBattleVehLevels()) def getPointsProgressForLevel(self, level): return self.__levelProgress[level] def getPointsForLevel(self, level): return sum( (self.__levelProgress[level] for level in xrange(level - 1))) def getLevelProgress(self): return self.__levelProgress def getLevelForPoints(self, points): lvl = 0 while points >= 0 and lvl <= self.__playerMaxLevel: points -= self.__levelProgress[lvl] lvl += 1 return lvl - 1 def getAllSkillsInformation(self): return self.__skillData def getPlayerLevelInfo(self): return self.__itemsCache.items.epicMetaGame.playerLevelInfo def getPlayerRanksInfo(self): if not self.__rankSettings: famePtsByRank = self.__metaSettings.metaLevel.get( 'famePtsByRank', {}) rankSettings = getRankSettings() self.__rankSettings = { rankLvl: (extraFamePts, rankSettings.bonus.factor100ByRank[rankLvl]) for rankLvl, extraFamePts in famePtsByRank.iteritems() } return self.__rankSettings def getSeasonData(self): return self.__itemsCache.items.epicMetaGame.seasonData def getSkillPoints(self): return self.__itemsCache.items.epicMetaGame.skillPoints def getSkillLevels(self): return self.__itemsCache.items.epicMetaGame.skillLevels def getSelectedSkills(self, vehicleCD): selected = self.__itemsCache.items.epicMetaGame.selectedSkills( vehicleCD) numSlots = self.getNumAbilitySlots(vehicles.getVehicleType(vehicleCD)) while len(selected) < numSlots: selected.append(-1) return selected def hasSuitableVehicles(self): requiredLevel = self.getModeSettings().validVehicleLevels v = self.__itemsCache.items.getVehicles( REQ_CRITERIA.INVENTORY | REQ_CRITERIA.VEHICLE.LEVELS(requiredLevel)) return len(v) > 0 def increaseSkillLevel(self, skillID): BigWorld.player().epicMetaGame.increaseAbility(skillID) def changeEquippedSkills(self, skillIDArray, vehicleCD, callback=None, classVehs=False): if classVehs: if callback is None: BigWorld.player().epicMetaGame.setSelectedAbilitiesVehsClass( skillIDArray, vehicleCD) else: BigWorld.player().epicMetaGame.setSelectedAbilitiesVehsClass( skillIDArray, vehicleCD, callback) elif callback is None: BigWorld.player().epicMetaGame.setSelectedAbilities( skillIDArray, vehicleCD) else: BigWorld.player().epicMetaGame.setSelectedAbilities( skillIDArray, vehicleCD, callback) return def getCycleInfo(self, cycleID=None): season = self.getCurrentSeason() if season is not None: return season.getCycleInfo(cycleID) else: _logger.warning('No current season') return def getCycleOrdinalNumber(self, cycleID): cycleInfo = self.getCycleInfo(cycleID) return cycleInfo.ordinalNumber if cycleInfo else None def getSeasonTimeRange(self): season = self.getCurrentSeason() or self.getNextSeason() if season is not None: cycles = season.getAllCycles() if cycles: cycles = list( sorted(cycles.values(), key=lambda c: c.ordinalNumber)) return (cycles[0].startDate, cycles[-1].endDate) return (0, 0) def getAllUnlockedSkillInfoBySkillId(self): return { skillID: skill.getSkillInfo() for skillID, skill in self.__skillData.iteritems() if skill.isActivated } def getUnlockedAbilityIds(self): return (skill.getSkillInfo().eqID for skill in self.getAllSkillsInformation().itervalues() if skill.isActivated and skill.getSkillInfo() is not None) def getStoredEpicDiscount(self): return BigWorld.player().epicMetaGame.getStoredDiscount() def getEventTimeLeft(self): timeLeft = self.getSeasonTimeRange( )[1] - time_utils.getCurrentLocalServerTimestamp() return timeLeft + 1 if timeLeft > 0 else time_utils.ONE_MINUTE def getStats(self): return self.__itemsCache.items.epicMetaGame @process def openURL(self, url=None): requestUrl = url or self.getModeSettings().url if requestUrl: parsedUrl = yield self.__urlMacros.parse(requestUrl) if parsedUrl: self.__showBrowserView(parsedUrl) def showCustomScreen(self, screen): if self.getModeSettings().url and EpicBattleScreens.hasValue(screen): self.openURL('/'.join((self.getModeSettings().url.strip('/'), screen.value.strip('/')))) def getNumAbilitySlots(self, vehicleType): vehClass = getVehicleClassFromVehicleType(vehicleType) return self.__metaSettings.defaultSlots.get(vehClass, 0) def getAbilitySlotsOrder(self, vehicleType): vehClass = getVehicleClassFromVehicleType(vehicleType) return self.__metaSettings.slots.get(vehClass, (0, 0, 0)) def getAbilitySlotsUnlockOrder(self, vehicleType): vehClass = getVehicleClassFromVehicleType(vehicleType) return self.__metaSettings.inBattleReservesByRank.get( 'slotActions').get(vehClass, [[0], [0], [0]]) def getAllLevelRewards(self): rewardsData = dict() allQuests = self.__eventsCache.getAllQuests() for questKey, questData in allQuests.iteritems(): if LEVELUP_TOKEN_TEMPLATE in questKey: _, _, questNum = questKey.partition(LEVELUP_TOKEN_TEMPLATE) if questNum: questLvl = int(questNum) rewardsData[questLvl] = questData return rewardsData def isNeedToTakeReward(self): currentLevel, _ = self.getPlayerLevelInfo() rewardsData = self.getAllLevelRewards() for bonuses in (rewards.getBonuses() for level, rewards in rewardsData.iteritems() if level <= currentLevel): for bonus in bonuses: if bonus.getName() == EPIC_SELECT_BONUS_NAME: for tokenID in bonus.getTokens().iterkeys(): if self.__itemsCache.items.tokens.getToken(tokenID): return True return False def getNotChosenRewardCount(self): count = 0 for token in self.__itemsCache.items.tokens.getTokens().iterkeys(): if not token.startswith(EPIC_CHOICE_REWARD_OFFER_GIFT_TOKENS): continue if not self.__offersProvider.getOfferByToken( token.replace('_gift', '')): continue if self.__itemsCache.items.tokens.isTokenAvailable(token): count += self.__itemsCache.items.tokens.getTokenCount(token) return count def hasAnyOfferGiftToken(self): return any((token.startswith(EPIC_CHOICE_REWARD_OFFER_GIFT_TOKENS) for token in self.__itemsCache.items.tokens.getTokens().iterkeys())) def replaceOfferByGift(self, bonuses): result = [] for bonus in bonuses: gift = self.__getReceivedGift(bonus) if gift: result.extend(gift.bonuses) result.append(bonus) return result def replaceOfferByReward(self, bonuses): result = [] for bonus in bonuses: if bool(self.__getReceivedGift(bonus)): bonus.updateContext({'isReceived': True}) result.append(bonus) return result def __getReceivedGift(self, bonus): if bonus.getName() == EPIC_SELECT_BONUS_NAME: bonus.updateContext({'isReceived': False}) for tokenID in bonus.getTokens().iterkeys(): offer = self.__offersProvider.getOfferByToken( tokenID.replace('_gift', '')) if offer: receivedGifts = self.__offersProvider.getReceivedGifts( offer.id) if receivedGifts: for giftId, count in receivedGifts.iteritems(): if count > 0: return offer.getGift(giftId) return None def __invalidateBattleAbilities(self, *_): if not self.__itemsCache.isSynced(): return self.__invalidateBattleAbilityItems() self.__invalidateBattleAbilitiesForVehicle() def __setData(self): self.__skillData = {} skills = self.__metaSettings.rewards.get('combatReserves', {}) maxSkillLvl = self.__metaSettings.maxCombatReserveLevel eqs = vehicles.g_cache.equipments() if skills != {}: for key, value in skills.iteritems(): self.__skillData[key] = EpicMetaGameSkill( key, maxSkillLvl, value.get('tags'), value.get('price', 0)) lvls = value['levels'] lvlAmount = len(lvls) found = 0 for eq in eqs.values(): if eq.name in lvls: lvl = lvls.index(eq.name) + 1 self.__skillData[key].levels[ lvl] = EpicMetaGameSkillLevel( lvl, eq.id[1], i18n.makeString(eq.userString), i18n.makeString(eq.shortDescription), i18n.makeString(eq.longDescription), i18n.makeString(eq.shortFilterAlert), i18n.makeString(eq.longFilterAlert), eq.icon[0]) found += 1 if found == lvlAmount: break metaLevel = self.__metaSettings.metaLevel self.__playerMaxLevel = metaLevel.get('maxLevel', 0) self.__stageLimit = metaLevel.get('stageLimit', -1) self.__abilityPointsForLevel = metaLevel.get('abilityPointsForLevel', []) levelProgress = metaLevel.get('famePtsToProgress', [])[:] levelProgress.insert(0, 0) self.__levelProgress = tuple(levelProgress) def __clear(self): self.stopNotification() self.stopGlobalListening() self.__lobbyContext.getServerSettings( ).onServerSettingsChange -= self.__updateEpicMetaGameSettings g_currentVehicle.onChanged -= self.__invalidateBattleAbilities self.__itemsCache.onSyncCompleted -= self.__invalidateBattleAbilities g_clientUpdateManager.removeObjectCallbacks(self) if self.getPerformanceGroup() == EPIC_PERF_GROUP.HIGH_RISK: self.__lobbyContext.deleteFightButtonConfirmator( self.__confirmFightButtonPressEnabled) def __updateEpic(self, diff): changes = set(diff.keys()) self.__invalidateBattleAbilities() if changes: self.onUpdated(diff) def __updateEpicMetaGameSettings(self, diff): if 'epic_config' in diff: self.__setData() self.onUpdated(diff['epic_config']) self.__resetTimer() def __resetTimer(self): self.startNotification() self.__timerUpdate() self.__timerTick() def __timerUpdate(self): status, _, _ = self.getPrimeTimeStatus() self.onPrimeTimeStatusUpdated(status) def __timerTick(self): self.onGameModeStatusTick() def __onEventEnded(self): self.onEventEnded() self.__eventEndedNotifier.stopNotification() self.__eventEndedNotifier.clear() def __showBattleResults(self, reusableInfo, _, resultsWindow): if reusableInfo.common.arenaBonusType == ARENA_BONUS_TYPE.EPIC_BATTLE: arenaUniqueID = reusableInfo.arenaUniqueID if arenaUniqueID not in self.__showedResultsForArenas: self.__showedResultsForArenas.append(arenaUniqueID) self.__showedResultsForArenas = self.__showedResultsForArenas[ -self.MAX_STORED_ARENAS_RESULTS:] extensionInfo = reusableInfo.personal.avatar.extensionInfo levelUpInfo = { 'metaLevel': extensionInfo.get('metaLevel'), 'prevMetaLevel': extensionInfo.get('prevMetaLevel'), 'playerRank': extensionInfo.get('playerRank'), 'originalFlXP': extensionInfo.get('originalFlXP'), 'boosterFlXP': extensionInfo.get('boosterFlXP') } event_dispatcher.showEpicBattlesAfterBattleWindow( levelUpInfo, resultsWindow) def __isInValidPrebattle(self): if g_prbLoader and g_prbLoader.getDispatcher( ) and g_prbLoader.getDispatcher().getEntity(): currentPrbEntity = g_prbLoader.getDispatcher().getEntity( ).getEntityType() return currentPrbEntity in (QUEUE_TYPE.EPIC, PREBATTLE_TYPE.EPIC, PREBATTLE_TYPE.EPIC_TRAINING) else: return None def __invalidateBattleAbilityItems(self): data = self.__itemsCache.items.getItems(GUI_ITEM_TYPE.BATTLE_ABILITY, REQ_CRITERIA.EMPTY) vehicle = g_currentVehicle.item for item in data.values(): if self.__isInValidPrebattle(): item.isUnlocked = item.innationID in self.getUnlockedAbilityIds( ) if vehicle is not None: mayInstall, _ = item.mayInstall(vehicle) if not mayInstall: item.isUnlocked = False item.isUnlocked = False return def __invalidateBattleAbilitiesForVehicle(self): vehicle = g_currentVehicle.item if vehicle is None or vehicle.descriptor.type.level not in self.__lobbyContext.getServerSettings( ).epicBattles.validVehicleLevels or not self.__isInValidPrebattle(): return else: amountOfSlots = self.getNumAbilitySlots(vehicle.descriptor.type) selectedItems = [None] * amountOfSlots skillInfo = self.getAllSkillsInformation() selectedSkills = self.getSelectedSkills(vehicle.intCD) battleAbilities = self.__itemsCache.items.getItems( GUI_ITEM_TYPE.BATTLE_ABILITY, REQ_CRITERIA.EMPTY) for item in battleAbilities.values(): for index, skillID in enumerate(selectedSkills): if skillID is not None and skillID >= 0: if skillInfo[skillID].getSkillInfo( ) and item.innationID == skillInfo[ skillID].getSkillInfo().eqID: selectedItems[index] = item vehicle.battleAbilities.setLayout(*selectedItems) vehicle.battleAbilities.setInstalled(*selectedItems) return def __analyzeClientSystem(self): stats = BigWorld.wg_getClientStatistics() stats['graphicsEngine'] = self.__settingsCore.getSetting( GRAPHICS.RENDER_PIPELINE) self.__performanceGroup = EPIC_PERF_GROUP.LOW_RISK for groupName, conditions in PERFORMANCE_GROUP_LIMITS.iteritems(): for currentLimit in conditions: condValid = True systemStats = currentLimit.get( EPIC_META_GAME_LIMIT_TYPE.SYSTEM_DATA, {}) for key, limit in systemStats.iteritems(): currValue = stats.get(key, None) if currValue is None or currValue != limit: condValid = False hardwareParams = currentLimit.get( EPIC_META_GAME_LIMIT_TYPE.HARDWARE_PARAMS, {}) for key, limit in hardwareParams.iteritems(): currValue = BigWorld.getAutoDetectGraphicsSettingsScore( key) if currValue >= limit: condValid = False if condValid: self.__performanceGroup = groupName return return def __onInventoryUpdate(self, invDiff): items = { GUI_ITEM_TYPE.VEHICLE, GUI_ITEM_TYPE.BATTLE_ABILITY, GUI_ITEM_TYPE.CUSTOMIZATION } if items.intersection(invDiff): self.__invalidateBattleAbilities() def __updateSounds(self, isEpicSoundMode): if isEpicSoundMode != self.__isEpicSoundMode: _FrontLineSounds.onChange(isEpicSoundMode) self.__isEpicSoundMode = isEpicSoundMode @async @process def __confirmFightButtonPressEnabled(self, callback): if not self.__isInValidPrebattle(): callback(True) return defaults = AccountSettings.getFilterDefault(GUI_START_BEHAVIOR) filters = self.__settingsCore.serverSettings.getSection( GUI_START_BEHAVIOR, defaults) isEpicPerformanceWarningEnabled = not AccountSettings.getSettings( 'isEpicPerformanceWarningClicked') if isEpicPerformanceWarningEnabled: result, checkboxChecked = yield DialogsInterface.showI18nCheckBoxDialog( 'epicBattleConfirmDialog') filters['isEpicPerformanceWarningClicked'] = checkboxChecked AccountSettings.setSettings('isEpicPerformanceWarningClicked', checkboxChecked) else: result = True callback(result) def __showBrowserView(self, url): from gui.Scaleform.daapi.view.lobby.epicBattle.web_handlers import createFrontlineWebHandlers webHandlers = createFrontlineWebHandlers() alias = VIEW_ALIAS.BROWSER_VIEW g_eventBus.handleEvent( events.LoadViewEvent(SFViewLoadParams(alias, getUniqueViewName(alias)), ctx={ 'url': url, 'webHandlers': webHandlers, 'returnAlias': VIEW_ALIAS.LOBBY_HANGAR, 'onServerSettingsChange': self.__serverSettingsChangeBrowserHandler }), EVENT_BUS_SCOPE.LOBBY) def __serverSettingsChangeBrowserHandler(self, browser, diff): if not diff.get(Configs.EPIC_CONFIG.value, {}).get('isEnabled'): browser.onCloseView() @property def __metaSettings(self): return self.__lobbyContext.getServerSettings().epicMetaGame def __onTokensUpdate(self, diff): if any((key.startswith(EPIC_CHOICE_REWARD_OFFER_GIFT_TOKENS) for key in diff.keys())): pass
class BattlePassVotingRequester(object): __slots__ = ('__battlePassController', '__isAvailableService', '__isStarted', '__requestNotifier', '__cache', '__eventsManager', 'onVotingResultsUpdated') __webController = dependency.descriptor(IWebController) CALLBACK_REPEAT_TIME = 60 def __init__(self, battlePassController): super(BattlePassVotingRequester, self).__init__() self.__battlePassController = weakref.proxy(battlePassController) self.__eventsManager = EventManager() self.__requestNotifier = SimpleNotifier( self.__getTimeToNotifyFailedRequest, self.__requestVotingData) self.__isStarted = False self.__isAvailableService = True self.__cache = {} self.onVotingResultsUpdated = Event(self.__eventsManager) def start(self): if not self.__isStarted: self.__isStarted = True self.__requestVotingData(self.__getDefaultSeasonIDs()) def getVotingResult(self, seasonID): result = {} if self.__cache.get(seasonID): result = self.__cache[seasonID] if seasonID == self.__battlePassController.getSeasonID(): self.__requestVotingData([seasonID]) else: self.__requestVotingData([seasonID]) return (self.__isAvailableService, result) def stop(self): self.__isStarted = False self.__requestNotifier.stopNotification() self.__eventsManager.clear() @process def __requestVotingData(self, seasons=None): if seasons is None: seasons = self.__getDefaultSeasonIDs() ctx = BattlePassGetVotingDataCtx(seasons) response = yield self.__webController.sendRequest(ctx=ctx) if not self.__isStarted: return else: self.__isAvailableService = response.isSuccess() result = {} if self.__isAvailableService: result = ctx.getDataObj(response.getData()) else: _logger.warning( 'Bad response from Get Battle Pass Voting Data') self.__requestNotifier.startNotification() self.__updateCache(result) return def __updateCache(self, votingResults): isCacheUpdated = False for seasonID, votingResult in votingResults.iteritems(): if not self.__cache.get(seasonID): self.__cache[seasonID] = votingResult isCacheUpdated = True continue for vehCD, countVoices in votingResult.iteritems(): if self.__cache[seasonID].get(vehCD) != countVoices: self.__cache[seasonID] = votingResult isCacheUpdated = True break if isCacheUpdated: self.onVotingResultsUpdated() def __getTimeToNotifyFailedRequest(self): return self.CALLBACK_REPEAT_TIME def __getDefaultSeasonIDs(self): result = [self.__battlePassController.getSeasonID()] allSeasonStats = self.__battlePassController.getPrevSeasonsStats() if not allSeasonStats: return result for seasonStats in allSeasonStats: result.append(seasonStats.seasonID) return result
class ResourceWellController(IResourceWellController, EventsHandler): __itemsCache = dependency.descriptor(IItemsCache) __lobbyContext = dependency.descriptor(ILobbyContext) def __init__(self): self.__eventsManager = EventManager() self.onEventUpdated = Event(self.__eventsManager) self.onSettingsChanged = Event(self.__eventsManager) self.onNumberRequesterUpdated = Event(self.__eventsManager) self.__notifier = SimpleNotifier(self.__getTimeLeft, self.__onEventStateChange) self.__serialNumberRequester = ResourceWellNumberRequester(isSerial=True) self.__regularNumberRequester = ResourceWellNumberRequester(isSerial=False) def onLobbyInited(self, event): self._subscribe() self.__notifier.startNotification() def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() def fini(self): self.__eventsManager.clear() self.__serialNumberRequester.clear() self.__regularNumberRequester.clear() self.__stop() def isEnabled(self): return self.__getConfig().isEnabled def isActive(self): return self.isEnabled() and self.isStarted() and not self.isFinished() def isStarted(self): return self.__getStartTime() <= time_utils.getServerUTCTime() def isFinished(self): return self.getFinishTime() <= time_utils.getServerUTCTime() def isPaused(self): return not self.isEnabled() and self.isStarted() and not self.isFinished() def getSeason(self): return self.__getConfig().season def getRewardLimit(self, isTop): return findFirst(lambda reward: reward.isSerial == isTop, self.__getConfig().rewards.itervalues()).limit def getFinishTime(self): return self.__getConfig().finishTime def getCurrentPoints(self): return self.__itemsCache.items.resourceWell.getCurrentPoints() def getMaxPoints(self): return self.__getConfig().points def getRewardVehicle(self): return first(first(self.__getConfig().rewards.itervalues()).bonus.get('vehicles', {}).keys()) def getRewardStyleID(self): topReward = findFirst(lambda reward: reward.isSerial, self.__getConfig().rewards.itervalues()) return first(topReward.bonus['vehicles'].values())['customization'].get('styleId', 0) def getRewardSequence(self, isTop): return findFirst(lambda reward: reward.isSerial == isTop, self.__getConfig().rewards.itervalues()).sequence def getRewardLeftCount(self, isTop): return self.__getSerialRewardLeftCount() if isTop else self.__getRegularRewardLeftCount() def isRewardEnabled(self, isTop): topRewardLeftCount = self.getRewardLeftCount(isTop=True) return isTop and topRewardLeftCount or not (isTop or topRewardLeftCount) def isRewardCountAvailable(self, isTop=True): requester = self.__serialNumberRequester if isTop else self.__regularNumberRequester return requester.isDataAvailable() def getReminderTime(self): return self.__getConfig().remindTime def isCompleted(self): return self.__itemsCache.items.resourceWell.getReward() is not None def getResources(self): return self.__getConfig().resources def getRewards(self): return self.__getConfig().rewards def getRewardID(self, isTop): return findFirst(lambda (rewardID, reward): reward.isSerial == isTop, self.getRewards().iteritems())[0] def startNumberRequesters(self): if self.isEnabled(): self.__serialNumberRequester.start() self.__regularNumberRequester.start() def stopNumberRequesters(self): self.__serialNumberRequester.stop() self.__regularNumberRequester.stop() def _getEvents(self): return ((self.__lobbyContext.getServerSettings().onServerSettingsChange, self.__onServerSettingsChanged), (self.__serialNumberRequester.onUpdated, self.__onRequesterUpdated), (self.__regularNumberRequester.onUpdated, self.__onRequesterUpdated)) def __getConfig(self): return self.__lobbyContext.getServerSettings().resourceWellConfig def __getTimeLeft(self): if not self.isStarted(): return max(0, self.__getStartTime() - time_utils.getServerUTCTime()) return max(0, self.getFinishTime() - time_utils.getServerUTCTime()) if not self.isFinished() else 0 def __getStartTime(self): return self.__getConfig().startTime def __onEventStateChange(self): self.onEventUpdated() def __getRegularRewardLeftCount(self): return self.__regularNumberRequester.getRemainingValues() or 0 def __getSerialRewardLeftCount(self): if not self.__serialNumberRequester.isDataAvailable(): return 0 remainingValuesCount = self.__serialNumberRequester.getRemainingValues() givenValuesCount = self.__serialNumberRequester.getGivenValues() rewardLimit = self.getRewardLimit(True) if remainingValuesCount > rewardLimit or givenValuesCount > rewardLimit: _logger.error('remainingValuesCount and givenValuesCount cannot exceed rewardLimit!') return 0 return remainingValuesCount if remainingValuesCount < rewardLimit / 2.0 else rewardLimit - givenValuesCount @serverSettingsChangeListener(Configs.RESOURCE_WELL.value) def __onServerSettingsChanged(self, diff): resourceWellDiff = diff[Configs.RESOURCE_WELL.value] if 'finishTime' in resourceWellDiff or 'startTime' in resourceWellDiff: self.__notifier.startNotification() self.onEventUpdated() if 'isEnabled' in resourceWellDiff: self.__notifier.startNotification() self.onEventUpdated() if not self.isActive(): self.stopNumberRequesters() self.onSettingsChanged() def __onRequesterUpdated(self): self.onNumberRequesterUpdated() def __stop(self): self._unsubscribe() self.__notifier.stopNotification() self.stopNumberRequesters()
class BattlePassVideoProvider(object): __slots__ = ('onVideosConfigUpdated', '__videosConfig', '__eventsManager', '__battlePassController', '__isStarted', '__unlockVideoNotifier', '__requestVideoNotifier', '__failedRequestCount', '__webController') SIZE_STORAGE = 16 CALLBACK_REPEAT_TIME = 20 __settingsCore = dependency.descriptor(ISettingsCore) def __init__(self, battlePassController): super(BattlePassVideoProvider, self).__init__() self.__battlePassController = weakref.proxy(battlePassController) self.__eventsManager = EventManager() self.__videosConfig = {} self.__unlockVideoNotifier = SimpleNotifier( self.__getTimeToNotifyUnlockVideo, self.__onNotifyUnlockVideo) self.__requestVideoNotifier = SimpleNotifier( self.__getTimeToNotifyFailedRequest, self.__onMakeRepeatRequest) self.__isStarted = False self.__failedRequestCount = 0 self.__webController = None self.onVideosConfigUpdated = Event(self.__eventsManager) return @property def isStarted(self): return self.__isStarted def start(self): self.__webController = BattlePassWebController() self.__webController.init() self.__webController.invalidate() self.__isStarted = True self.__requestVideoData() self.__battlePassController.onLevelUp += self.__onLevelUp def stop(self): self.__isStarted = False self.__failedRequestCount = 0 self.__battlePassController.onLevelUp -= self.__onLevelUp self.__unlockVideoNotifier.stopNotification() self.__requestVideoNotifier.stopNotification() if self.__webController is not None: self.__webController.fini() self.__webController = None return def getVideosTotal(self): return len(self.__videosConfig) def getAvailableVideosCount(self): return len(self.__getAvailableVideos()) def hasUnviewedVideo(self): return True if self.getAvailableVideosCount() > len( self.getViewedVideos()) else False def setShownVideo(self, videoID): self.__saveShownVideoInStorage(videoID) self.onVideosConfigUpdated() def getViewedVideos(self): shownVideoFlags = self.__settingsCore.serverSettings.getBPStorage( ).get(BattlePassStorageKeys.SHOWN_VIDEOS_FLAGS) result = [] for videoID, video in self.__videosConfig.items(): videoIndex = video.get('idx') if shownVideoFlags & 1 << videoIndex: result.append(videoID) return result def __saveShownVideoInStorage(self, videoID): offset = self.__getShownFlagOffset(self.__videosConfig, videoID) if offset is None: _logger.warning('Failed to save shown video') return else: shownVideoFlags = self.__settingsCore.serverSettings.getBPStorage( ).get(BattlePassStorageKeys.SHOWN_VIDEOS_FLAGS) self.__settingsCore.serverSettings.saveInBPStorage({ BattlePassStorageKeys.SHOWN_VIDEOS_FLAGS: shownVideoFlags | 1 << offset }) return def __resetShownVideoInStorage(self, videoID): offset = self.__getShownFlagOffset(self.__videosConfig, videoID) if offset is None: _logger.warning('Failed to clear save shown video') return else: shownVideoFlags = self.__settingsCore.serverSettings.getBPStorage( ).get(BattlePassStorageKeys.SHOWN_VIDEOS_FLAGS) if shownVideoFlags: self.__settingsCore.serverSettings.saveInBPStorage({ BattlePassStorageKeys.SHOWN_VIDEOS_FLAGS: shownVideoFlags & ~(1 << offset) }) return def __getAvailableVideos(self): result = [] for video in self.__videosConfig.values(): if video.get('is_available'): result.append(video) return result def __getTimeToNotifyUnlockVideo(self): if not self.__videosConfig: return 0 serverVideosIDs = self.__getVideoIndexAndIDFromConfig( self.__videosConfig) for videoIndex in sorted(serverVideosIDs.keys()): video = self.__videosConfig[serverVideosIDs[videoIndex]] if not video.get('is_available'): publicationTime = video.get('condition', {}).get('publication_start', 0) return max(0, publicationTime - time_utils.getServerUTCTime()) def __updateVideosConfig(self): for video in self.__videosConfig.values(): if not video.get('is_available'): publicationTime = video.get('publication_start') needLevel = video.get('level') needVote = video.get('need_vote') if publicationTime > time_utils.getServerUTCTime(): continue if needLevel > self.__battlePassController.getCurrentLevel(): continue if needVote and not self.__battlePassController.isPlayerVoted( ): continue self.__requestVideoData() break def __onLevelUp(self): self.__updateVideosConfig() def __onNotifyUnlockVideo(self): self.__updateVideosConfig() def __getTimeToNotifyFailedRequest(self): time = self.CALLBACK_REPEAT_TIME * 2**self.__failedRequestCount self.__failedRequestCount += 1 return time def __onMakeRepeatRequest(self): self.__requestVideoData() @process def __requestVideoData(self): if self.__battlePassController.isPlayerVoted(): voteID = self.__battlePassController.getVoteOption() isBought = self.__isVotedWithBoughtBP() else: voteID = None isBought = self.__battlePassController.isBought() ctx = BattlePassGetVideoDataCtx( self.__battlePassController.getSeasonID(), self.__battlePassController.getCurrentLevel(), int(isBought), voteID) response = yield self.__webController.sendRequest(ctx=ctx) if not self.__isStarted: return else: if response.isSuccess(): self.__videosConfig = ctx.getDataObj(response.getData()) self.__checkConflicts() self.__unlockVideoNotifier.startNotification() self.__failedRequestCount = 0 self.onVideosConfigUpdated() else: self.__requestVideoNotifier.startNotification() return def __checkConflicts(self): localConfig = AccountSettings.getSettings(BATTLE_PASS_VIDEOS_CONFIG) localVideosIDs = self.__getVideoIndexAndIDFromConfig(localConfig) serverVideosIDs = self.__getVideoIndexAndIDFromConfig( self.__videosConfig) if not localConfig: AccountSettings.setSettings(BATTLE_PASS_VIDEOS_CONFIG, self.__videosConfig) localVideosIDs = self.__getVideoIndexAndIDFromConfig( self.__videosConfig) for videoIdx in serverVideosIDs.keys(): localVideoID = localVideosIDs.get(videoIdx) serverVideoID = serverVideosIDs[videoIdx] if localVideoID is None or localVideoID != serverVideoID: self.__resetShownVideoInStorage(serverVideoID) localConfig.pop(localVideoID, None) localConfig[serverVideoID] = self.__videosConfig[serverVideoID] AccountSettings.setSettings(BATTLE_PASS_VIDEOS_CONFIG, localConfig) return def __isVotedWithBoughtBP(self): return self.__settingsCore.serverSettings.getBPStorage().get( BattlePassStorageKeys.VOTED_WITH_BOUGHT_BP) @staticmethod def __getVideoIndexAndIDFromConfig(config): return {video.get('idx'): videoID for videoID, video in config.items()} @staticmethod def __getShownFlagOffset(config, videoID): video = config.get(videoID, None) if video is None: _logger.error( 'Failed to get video! Check videos config are correct.') return else: return video.get('idx')
class EpicBattleMetaGameController(Notifiable, SeasonProvider, IEpicBattleMetaGameController, IGlobalListener): bootcampController = dependency.descriptor(IBootcampController) __itemsCache = dependency.descriptor(IItemsCache) __settingsCore = dependency.descriptor(ISettingsCore) __lobbyContext = dependency.descriptor(ILobbyContext) __battleResultsService = dependency.descriptor(IBattleResultsService) MAX_STORED_ARENAS_RESULTS = 20 TOKEN_QUEST_ID = 'epicmetagame:levelup:' DAILY_QUEST_ID = 'front_line' MODE_ALIAS = 'frontline' def __init__(self): super(EpicBattleMetaGameController, self).__init__() self._setSeasonSettingsProvider(self.getModeSettings) self._setPrimeTimesIteratorGetter(self.getPrimeTimesIter) self.onUpdated = Event.Event() self.onPrimeTimeStatusUpdated = Event.Event() self.onEventEnded = Event.Event() self.__skillData = {} self.__playerMaxLevel = 0 self.__playerMaxPrestigeLevel = 0 self.__levelProgress = tuple() self.__isNow = False self.__inEpicPrebattle = False self.__performanceGroup = None self.__isFrSoundMode = False self.__rankSettings = {} self.__showedResultsForArenas = [] self.__eventEndedNotifier = None return def init(self): super(EpicBattleMetaGameController, self).init() self.addNotificator(SimpleNotifier(self.getTimer, self.__timerUpdate)) self.__eventEndedNotifier = SimpleNotifier(self.getEventTimeLeft, self.__onEventEnded) self.addNotificator(self.__eventEndedNotifier) def fini(self): del self.__showedResultsForArenas[:] self.onUpdated.clear() self.onPrimeTimeStatusUpdated.clear() self.clearNotification() self.stopGlobalListening() super(EpicBattleMetaGameController, self).fini() def onLobbyInited(self, ctx): self.__lobbyContext.getServerSettings().onServerSettingsChange += self.__updateEpicMetaGameSettings g_currentVehicle.onChanged += self.__invalidateBattleAbilities self.__itemsCache.onSyncCompleted += self.__invalidateBattleAbilities g_clientUpdateManager.addCallbacks({'epicMetaGame': self.__updateEpic, 'inventory': self.__onInventoryUpdate}) self.startGlobalListening() self.__setData() self.__invalidateBattleAbilities() self.startNotification() if self.getPerformanceGroup() == EPIC_PERF_GROUP.HIGH_RISK: self.__lobbyContext.addFightButtonConfirmator(self.__confirmFightButtonPressEnabled) self.__isFrSoundMode = False self.__updateSounds() def onDisconnected(self): self.__clear() def onPrbEntitySwitched(self): self.__invalidateBattleAbilities() self.__updateSounds() def onAccountBecomePlayer(self): self.__battleResultsService.onResultPosted += self.__showBattleResults def onAvatarBecomePlayer(self): self.__clear() self.__battleResultsService.onResultPosted -= self.__showBattleResults def isEnabled(self): return self.getModeSettings().isEnabled def isReservesAvailableInFLMenu(self): return self.getModeSettings().reservesAvailableInFLMenu def getPerformanceGroup(self): if not self.__performanceGroup: self.__analyzeClientSystem() _logger.debug('Current performance group %s', self.__performanceGroup) return self.__performanceGroup def getMaxPlayerLevel(self): return self.__playerMaxLevel def getMaxPlayerPrestigeLevel(self): return self.__playerMaxPrestigeLevel def getStageLimit(self): return self.__stageLimit def getPointsProgressForLevel(self, level): return self.__levelProgress[level] def getPointsForLevel(self, level): return sum((self.__levelProgress[level] for level in xrange(level - 1))) def getLevelProgress(self): return self.__levelProgress def getLevelForPoints(self, points): lvl = 0 while points >= 0 and lvl <= self.__playerMaxLevel: points -= self.__levelProgress[lvl] lvl += 1 return lvl - 1 def getAllSkillsInformation(self): return self.__skillData def getPlayerLevelInfo(self): return self.__itemsCache.items.epicMetaGame.playerLevelInfo def getPlayerRanksInfo(self): if not self.__rankSettings: famePtsByRank = self.__getSettings().metaLevel.get('famePtsByRank', {}) rankSettings = getRankSettings() self.__rankSettings = {rankLvl:(extraFamePts, rankSettings.bonus.factor100ByRank[rankLvl]) for rankLvl, extraFamePts in famePtsByRank.iteritems()} return self.__rankSettings def getSeasonData(self): return self.__itemsCache.items.epicMetaGame.seasonData def getSkillPoints(self): return self.__itemsCache.items.epicMetaGame.skillPoints def getSkillLevels(self): return self.__itemsCache.items.epicMetaGame.skillLevels def getSelectedSkills(self, vehicleCD): selected = self.__itemsCache.items.epicMetaGame.selectedSkills(vehicleCD) numSlots = self.getNumAbilitySlots(vehicles.getVehicleType(vehicleCD)) while len(selected) < numSlots: selected.append(-1) return selected def hasSuitableVehicles(self): requiredLevel = self.getModeSettings().validVehicleLevels v = self.__itemsCache.items.getVehicles(REQ_CRITERIA.INVENTORY | REQ_CRITERIA.VEHICLE.LEVELS(requiredLevel)) return len(v) > 0 def increaseSkillLevel(self, skillID): BigWorld.player().epicMetaGame.increaseAbility(skillID) def changeEquippedSkills(self, skillIDArray, vehicleCD, callback=None): if callback is None: BigWorld.player().epicMetaGame.setSelectedAbilities(skillIDArray, vehicleCD) else: BigWorld.player().epicMetaGame.setSelectedAbilities(skillIDArray, vehicleCD, callback) return def getCycleInfo(self, cycleID=None): season = self.getCurrentSeason() if season is not None: cycleInfo = season.getCycleInfo(cycleID) if cycleInfo is not None: return cycleInfo _logger.warning('Cycle with id "%s" not found', cycleID) _logger.warning('No current season') return def getCycleOrdinalNumber(self, cycleID): cycleInfo = self.getCycleInfo(cycleID) return cycleInfo.ordinalNumber if cycleInfo else None def getSeasonTimeRange(self): season = self.getCurrentSeason() or self.getNextSeason() if season is not None: cycles = season.getAllCycles() if cycles: cycles = list(sorted(cycles.values(), key=lambda c: c.ordinalNumber)) return (cycles[0].startDate, cycles[-1].endDate) return (0, 0) def getAllUnlockedSkillLevels(self): return chain.from_iterable((skill.getAllUnlockedSkillLevels() for skill in self.__skillData.itervalues())) def getAllUnlockedSkillLevelsBySkillId(self): return {skillID:skill.getAllUnlockedSkillLevels() for skillID, skill in self.__skillData.iteritems()} def getUnlockedAbilityIds(self): return (lvl.eqID for lvl in (skill.getMaxUnlockedSkillLevel() for skill in self.getAllSkillsInformation().itervalues()) if lvl is not None) def getStoredEpicDiscount(self): return BigWorld.player().epicMetaGame.getStoredDiscount() def isWelcomeScreenUpToDate(self, serverSettings): lastSeen = serverSettings.getSectionSettings(GUI_START_BEHAVIOR, 'lastShownEpicWelcomeScreen') currentVersion = getCurrentWelcomeScreenVersion() return lastSeen >= currentVersion def getEventTimeLeft(self): timeLeft = self.getSeasonTimeRange()[1] - time_utils.getCurrentLocalServerTimestamp() return timeLeft + 1 if timeLeft > 0 else time_utils.ONE_MINUTE def getStats(self): return self.__itemsCache.items.epicMetaGame def getNumAbilitySlots(self, vehicleType): config = self.__lobbyContext.getServerSettings().epicMetaGame vehClass = getVehicleClassFromVehicleType(vehicleType) return config.defaultSlots.get(vehClass, 0) def __invalidateBattleAbilities(self, *_): if not self.__itemsCache.isSynced(): return self.__invalidateBattleAbilityItems() self.__invalidateBattleAbilitiesForVehicle() def __setData(self): self.__skillData = {} skills = self.__getSettings().rewards.get('combatReserves', {}) maxSkillLvl = self.__getSettings().maxCombatReserveLevel eqs = vehicles.g_cache.equipments() if skills != {}: for key, value in skills.iteritems(): self.__skillData[key] = EpicMetaGameSkill(key, maxSkillLvl) lvls = value['levels'] lvlAmount = len(lvls) found = 0 for eq in eqs.values(): if eq.name in lvls: lvl = lvls.index(eq.name) + 1 self.__skillData[key].levels[lvl] = EpicMetaGameSkillLevel(lvl, eq.id[1], i18n.makeString(eq.userString), i18n.makeString(eq.shortDescription), i18n.makeString(eq.longDescription), i18n.makeString(eq.shortFilterAlert), i18n.makeString(eq.longFilterAlert), eq.icon[0]) found += 1 if found == lvlAmount: break metaLevel = self.__getSettings().metaLevel self.__playerMaxLevel = metaLevel.get('maxLevel', 0) self.__playerMaxPrestigeLevel = metaLevel.get('maxPrestigeLevel', 0) self.__stageLimit = metaLevel.get('stageLimit', -1) levelProgress = metaLevel.get('famePtsToProgress', [])[:] levelProgress.insert(0, 0) self.__levelProgress = tuple(levelProgress) def __clear(self): self.stopNotification() self.stopGlobalListening() self.__lobbyContext.getServerSettings().onServerSettingsChange -= self.__updateEpicMetaGameSettings g_currentVehicle.onChanged -= self.__invalidateBattleAbilities self.__itemsCache.onSyncCompleted -= self.__invalidateBattleAbilities g_clientUpdateManager.removeObjectCallbacks(self) if self.getPerformanceGroup() == EPIC_PERF_GROUP.HIGH_RISK: self.__lobbyContext.deleteFightButtonConfirmator(self.__confirmFightButtonPressEnabled) def __updateEpic(self, diff): changes = set(diff.keys()) self.__invalidateBattleAbilities() if changes: self.onUpdated(diff) def __updateEpicMetaGameSettings(self, diff): if 'epic_config' in diff: self.__setData() self.onUpdated(diff) self.__resetTimer() def __resetTimer(self): self.startNotification() self.__timerUpdate() def __timerUpdate(self): status, _, _ = self.getPrimeTimeStatus() self.onPrimeTimeStatusUpdated(status) def __onEventEnded(self): self.onEventEnded() self.__eventEndedNotifier.stopNotification() self.__eventEndedNotifier.clear() def __showBattleResults(self, reusableInfo, _): if reusableInfo.common.arenaBonusType == ARENA_BONUS_TYPE.EPIC_BATTLE: arenaUniqueID = reusableInfo.arenaUniqueID if arenaUniqueID not in self.__showedResultsForArenas: self.__showedResultsForArenas.append(arenaUniqueID) self.__showedResultsForArenas = self.__showedResultsForArenas[-self.MAX_STORED_ARENAS_RESULTS:] event_dispatcher.showEpicBattlesAfterBattleWindow(reusableInfo) def __isInValidPrebattle(self): if g_prbLoader and g_prbLoader.getDispatcher() and g_prbLoader.getDispatcher().getEntity(): currentPrbEntity = g_prbLoader.getDispatcher().getEntity().getEntityType() return currentPrbEntity in (QUEUE_TYPE.EPIC, PREBATTLE_TYPE.EPIC, PREBATTLE_TYPE.EPIC_TRAINING) else: return None def __invalidateBattleAbilityItems(self): data = self.__itemsCache.items.getItems(GUI_ITEM_TYPE.BATTLE_ABILITY, REQ_CRITERIA.EMPTY) for item in data.values(): if self.__isInValidPrebattle(): newLevel = next((lvl.level for lvl in chain.from_iterable((skillInfo.levels.itervalues() for skillInfo in self.getAllSkillsInformation().itervalues())) if lvl.eqID == item.innationID), 0) item.setLevel(newLevel) item.isUnlocked = item.innationID in self.getUnlockedAbilityIds() item.setLevel(0) item.isUnlocked = False def __invalidateBattleAbilitiesForVehicle(self): vehicle = g_currentVehicle.item if vehicle is None or vehicle.descriptor.type.level not in self.__lobbyContext.getServerSettings().epicBattles.validVehicleLevels or not self.__isInValidPrebattle(): return else: amountOfSlots = self.getNumAbilitySlots(vehicle.descriptor.type) selectedItems = [None] * amountOfSlots skillInfo = self.getAllSkillsInformation() selectedSkills = self.getSelectedSkills(vehicle.intCD) battleAbilities = self.__itemsCache.items.getItems(GUI_ITEM_TYPE.BATTLE_ABILITY, REQ_CRITERIA.EMPTY) for item in battleAbilities.values(): for index, skillID in enumerate(selectedSkills): if skillID is not None and skillID >= 0: if skillInfo[skillID].getMaxUnlockedSkillLevel() and item.innationID == skillInfo[skillID].getMaxUnlockedSkillLevel().eqID: selectedItems[index] = item vehicle.battleAbilities.setLayout(*selectedItems) vehicle.battleAbilities.setInstalled(*selectedItems) return def __analyzeClientSystem(self): stats = BigWorld.wg_getClientStatistics() stats['graphicsEngine'] = self.__settingsCore.getSetting(GRAPHICS.RENDER_PIPELINE) self.__performanceGroup = EPIC_PERF_GROUP.LOW_RISK for groupName, conditions in PERFORMANCE_GROUP_LIMITS.iteritems(): for currentLimit in conditions: condValid = True systemStats = currentLimit.get(EPIC_META_GAME_LIMIT_TYPE.SYSTEM_DATA, {}) for key, limit in systemStats.iteritems(): currValue = stats.get(key, None) if currValue is None or currValue != limit: condValid = False hardwareParams = currentLimit.get(EPIC_META_GAME_LIMIT_TYPE.HARDWARE_PARAMS, {}) for key, limit in hardwareParams.iteritems(): currValue = BigWorld.getAutoDetectGraphicsSettingsScore(key) if currValue >= limit: condValid = False if condValid: self.__performanceGroup = groupName return return def __onInventoryUpdate(self, invDiff): if GUI_ITEM_TYPE.VEHICLE or GUI_ITEM_TYPE.BATTLE_ABILITY or GUI_ITEM_TYPE.CUSTOMIZATION in invDiff: self.__invalidateBattleAbilities() def __updateSounds(self): if self.prbEntity is None: return else: isFrSoundMode = bool(self.prbEntity.getModeFlags() & FUNCTIONAL_FLAG.EPIC) if isFrSoundMode != self.__isFrSoundMode: _FrontLineSounds.onChange(isFrSoundMode) self.__isFrSoundMode = isFrSoundMode return def getPrimeTimesIter(self, primeTimes): for primeTime in primeTimes: yield primeTime @async @process def __confirmFightButtonPressEnabled(self, callback): if not self.__isInValidPrebattle(): callback(True) return defaults = AccountSettings.getFilterDefault(GUI_START_BEHAVIOR) filters = self.__settingsCore.serverSettings.getSection(GUI_START_BEHAVIOR, defaults) isEpicPerformanceWarningEnabled = not AccountSettings.getSettings('isEpicPerformanceWarningClicked') if isEpicPerformanceWarningEnabled: result, checkboxChecked = yield DialogsInterface.showI18nCheckBoxDialog('epicBattleConfirmDialog') filters['isEpicPerformanceWarningClicked'] = checkboxChecked AccountSettings.setSettings('isEpicPerformanceWarningClicked', checkboxChecked) else: result = True callback(result) @staticmethod def __getSettings(): lobbyContext = dependency.instance(ILobbyContext) generalSettings = lobbyContext.getServerSettings().epicMetaGame return generalSettings @staticmethod def getModeSettings(): lobbyContext = dependency.instance(ILobbyContext) generalSettings = lobbyContext.getServerSettings().epicBattles return generalSettings
class BattlePassController(IBattlePassController): __itemsCache = dependency.descriptor(IItemsCache) __lobbyContext = dependency.descriptor(ILobbyContext) __offersProvider = dependency.descriptor(IOffersDataProvider) def __init__(self): self.__oldPoints = 0 self.__oldLevel = 0 self.__currentMode = None self.__eventsManager = EventManager() self.__seasonChangeNotifier = SimpleNotifier( self.__getTimeToNotifySeasonChange, self.__onNotifySeasonChange) self.onPointsUpdated = Event(self.__eventsManager) self.onLevelUp = Event(self.__eventsManager) self.onBattlePassIsBought = Event(self.__eventsManager) self.onSeasonStateChange = Event(self.__eventsManager) self.onBattlePassSettingsChange = Event(self.__eventsManager) self.onFinalRewardStateChange = Event(self.__eventsManager) self.onDeviceSelectChange = Event(self.__eventsManager) self.onOffersUpdated = Event(self.__eventsManager) self.onRewardSelectChange = Event(self.__eventsManager) self.__nonSelectedOldTrophyDeviceNotifier = NonSelectedOldTrophyDeviceNotifier( self) self.__rewardLogic = None return def init(self): super(BattlePassController, self).init() g_clientUpdateManager.addCallbacks({'tokens': self.__onTokensUpdate}) self.__rewardLogic = BattlePassRewardLogic(BattlePassStateMachine()) BattlePassAwardsManager.init() def onLobbyInited(self, event): self.__lobbyContext.getServerSettings( ).onServerSettingsChange += self.__onServerSettingsChange self.__itemsCache.onSyncCompleted += self.__onSyncCompleted self.__offersProvider.onOffersUpdated += self.__onOffersUpdated self.__seasonChangeNotifier.startNotification() self.__rewardLogic.start() if self.__currentMode is None: self.__currentMode = self.__getConfig().mode else: self.onBattlePassSettingsChange(self.__getConfig().mode, self.__currentMode) self.__currentMode = self.__getConfig().mode self.__nonSelectedOldTrophyDeviceNotifier.start() return def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__stop() self.__clearFields() self.__rewardLogic.stop() def fini(self): self.__stop() self.__rewardLogic.stop() self.__clearFields() self.__eventsManager.clear() g_clientUpdateManager.removeObjectCallbacks(self) super(BattlePassController, self).fini() def isBought(self, seasonID=None, chapter=None): if seasonID is None: seasonID = self.getSeasonID() if chapter is None: chapter = self.getCurrentChapter() tokenForAllBP = self.__itemsCache.items.tokens.getTokens().get( getBattlePassPassTokenName(seasonID, 0)) if tokenForAllBP is not None: return True else: token = self.__itemsCache.items.tokens.getTokens().get( getBattlePassPassTokenName(seasonID, chapter)) return token is not None def isOfferEnabled(self): return self.__lobbyContext.getServerSettings().isOffersEnabled() def isEnabled(self): return self.__getConfig().isEnabled() def isActive(self): return self.__getConfig().isActive(time_utils.getServerUTCTime()) def isVisible(self): return self.isSeasonStarted( ) and not self.isDisabled() and not self.isSeasonFinished() def isOffSeasonEnable(self): return False def isDisabled(self): return not self.isActive() and not self.isPaused() def isPaused(self): return self.__getConfig().isPaused() def isSeasonStarted(self): return self.__getConfig().seasonStart <= time_utils.getServerUTCTime() def isSeasonFinished(self): return self.__getConfig().seasonFinish <= time_utils.getServerUTCTime() def isValidBattleType(self, prbEntity): return prbEntity.getQueueType() in (constants.QUEUE_TYPE.RANDOMS, constants.QUEUE_TYPE.MAPBOX) def isGameModeEnabled(self, arenaBonusType): return self.__getConfig().isGameModeEnabled(arenaBonusType) def getSupportedArenaBonusTypes(self): return [arenaBonusType for arenaBonusType in self.__getConfig().points] def getMaxLevel(self): return self.__getConfig().maxBaseLevel def isRareLevel(self, level): realLevel = min(level, self.getMaxLevel()) tags = self.__getConfig().getTags(realLevel, BattlePassConsts.REWARD_PAID) return BattlePassConsts.RARE_REWARD_TAG in tags def isFinalLevel(self, level): realLevel = min(level, self.getMaxLevel()) return realLevel in self.getChapterConfig() def getOldTrophySelectTokensCount(self): return self.__itemsCache.items.tokens.getTokenCount( BATTLE_PASS_TOKEN_TROPHY_GIFT_OFFER_2020) def getOldNewDeviceSelectTokensCount(self): return self.__itemsCache.items.tokens.getTokenCount( BATTLE_PASS_TOKEN_NEW_DEVICE_GIFT_OFFER_2020) def getRewardLogic(self): return self.__rewardLogic def getSingleAward(self, level, awardType=BattlePassConsts.REWARD_FREE, needSort=True): reward = {} if awardType in (BattlePassConsts.REWARD_FREE, BattlePassConsts.REWARD_PAID): reward = self.__getConfig().getRewardByType(level, awardType) elif awardType == BattlePassConsts.REWARD_BOTH: rewards = [ self.__getConfig().getFreeReward(level), self.__getConfig().getPaidReward(level) ] return BattlePassAwardsManager.hideInvisible( BattlePassAwardsManager.composeBonuses(rewards)) if needSort: rewards = BattlePassAwardsManager.composeBonuses([reward]) else: rewards = awardsFactory(reward) return BattlePassAwardsManager.hideInvisible(rewards, needSplit=not needSort) def getAwardsInterval(self, fromLevel, toLevel, awardType=BattlePassConsts.REWARD_FREE): result = {} for level in range(fromLevel, toLevel + 1): result[level] = self.getSingleAward(level, awardType, True) return result def getPackedAwardsInterval(self, fromLevel, toLevel, awardType=BattlePassConsts.REWARD_FREE): result = [] for level in range(fromLevel, toLevel + 1): result.extend(self.getSingleAward(level, awardType, False)) return BattlePassAwardsManager.sortBonuses(result) def isNeedToTakeReward(self, awardType, level): bonuses = self.getSingleAward(level, awardType) if level > self.getCurrentLevel(): return False else: for bonus in bonuses: if bonus.getName() in (BATTLE_PASS_SELECT_BONUS_NAME, BATTLE_PASS_STYLE_PROGRESS_BONUS_NAME): for tokenID in bonus.getTokens().iterkeys(): if self.__itemsCache.items.tokens.getToken( tokenID) is not None: return True return False def replaceOfferByReward(self, bonuses): result = [] for bonus in bonuses: if bonus.getName() == BATTLE_PASS_SELECT_BONUS_NAME: hasGift = False for tokenID in bonus.getTokens().iterkeys(): offerToken = getOfferTokenByGift(tokenID) offer = self.__offersProvider.getOfferByToken(offerToken) if offer is not None: receivedGifts = self.__offersProvider.getReceivedGifts( offer.id) if receivedGifts: for giftId, count in receivedGifts.iteritems(): if count > 0: gift = offer.getGift(giftId) if gift is not None: hasGift = True result.extend(gift.bonuses) if not hasGift: result.append(bonus) result.append(bonus) return result def isChooseRewardEnabled(self, awardType, level): if level > self.getCurrentLevel(): return False else: bonuses = self.getSingleAward(level, awardType) for bonus in bonuses: if bonus.getName() == BATTLE_PASS_STYLE_PROGRESS_BONUS_NAME: return True if bonus.getName() == BATTLE_PASS_SELECT_BONUS_NAME: for tokenID in bonus.getTokens().iterkeys(): if self.__itemsCache.items.tokens.getToken( tokenID) is not None: return self.isOfferEnabled( ) and self.__offersProvider.getOfferByToken( getOfferTokenByGift(tokenID)) is not None return False def canChooseAnyReward(self): return False if not self.isOfferEnabled() else any(( token.startswith(BATTLE_PASS_CHOICE_REWARD_OFFER_GIFT_TOKENS) for token in self.__itemsCache.items.tokens.getTokens().iterkeys() if self.__offersProvider.getOfferByToken(getOfferTokenByGift( token)) is not None)) def getLevelsConfig(self): return self.__getConfig().basePoints def getFinalRewards(self): return {} def getFreeFinalRewardDict(self): return self.__getConfig().getRewardByType(self.getMaxLevel(), BattlePassConsts.REWARD_FREE) def getCurrentPoints(self): return self.__itemsCache.items.battlePass.getPoints() def getMaxPoints(self): return self.__getConfig().maxBasePoints def getCurrentLevel(self): return self.__itemsCache.items.battlePass.getCurrentLevel() def getCurrentChapter(self): return self.__getConfig().getChapter(self.getCurrentLevel()) def getChapterByLevel(self, level): return self.__getConfig().getChapter(level) def getState(self): return self.__itemsCache.items.battlePass.getState() def getPrevSeasonsStats(self): packedStats = self.__itemsCache.items.battlePass.getPackedStats() if not packedStats: return None else: unpackStats, _ = BattlePassStatsCommon.unpackAllSeasonStats( packedStats) return unpackStats def getLastFinishedSeasonStats(self): allSeasonStats = self.getPrevSeasonsStats() if not allSeasonStats: seasons = sorted(self.getSeasonsHistory().keys(), reverse=True) return BattlePassStatsCommon.makeSeasonStats( first(seasons), {}, BattlePassStatsCommon.initialSeasonStatsData()) return allSeasonStats[-1] def getSeasonsHistory(self): return self.__getConfig().seasonsHistory def getLevelPoints(self, level): levelsConfig = self.getLevelsConfig() return levelsConfig[ 0] if level <= 0 else levelsConfig[level] - levelsConfig[level - 1] def getFullChapterPoints(self, chapter, includeCurrent): levelsConfig = self.getLevelsConfig() minLevel, maxLevel = self.getChapterLevelInterval(chapter) if minLevel == maxLevel == 0: return 0 if includeCurrent: return levelsConfig[maxLevel - 1] return 0 if minLevel <= 1 else levelsConfig[minLevel - 2] def getLevelProgression(self): if self.isDisabled(): return (0, 0) level = self.getCurrentLevel() if level >= self.getMaxLevel(): levelsConfig = self.getLevelsConfig() points = levelsConfig[-1] - levelsConfig[-2] return (points, points) points = self.getCurrentPoints() levelsConfig = self.getLevelsConfig() return getLevelProgression(level, points, levelsConfig) def getLevelByPoints(self, points): if points >= self.getMaxPoints(): level = self.getMaxLevel() else: levelsConfig = self.getLevelsConfig() level = getLevel(curPoints=points, levelPoints=levelsConfig) chapter = self.__getConfig().getChapter(level) return (chapter, level) def getProgressionByPoints(self, points, level): levelsConfig = self.getLevelsConfig() if level >= self.getMaxLevel(): levelPoints = fullLevelPoints = levelsConfig[-1] - levelsConfig[-2] else: levelPoints, fullLevelPoints = getLevelProgression( level, points, levelsConfig) return (levelPoints, fullLevelPoints) def getPerBattlePoints(self, gameMode=constants.ARENA_BONUS_TYPE.REGULAR, vehCompDesc=None): winList = self.__getPackedBonusPointsList(vehTypeCompDescr=vehCompDesc, gameMode=gameMode) lostList = self.__getPackedBonusPointsList( vehTypeCompDescr=vehCompDesc, isWinner=False, gameMode=gameMode) count = 0 result = [] for winInfo, lostInfo in zip(winList, lostList): pointsWin, pointsCount = winInfo pointsLost, _ = lostInfo count += pointsCount if pointsWin > 0: item = TopPoints(count, pointsWin, pointsLost) result.append(item) return result def getPerBattleRoyalePoints( self, gameMode=constants.ARENA_BONUS_TYPE.BATTLE_ROYALE_SOLO, vehCompDesc=None): winList = self.__getPackedBonusPointsList(vehTypeCompDescr=vehCompDesc, gameMode=gameMode) pointList = self.__getPackedBonusPointsList( vehTypeCompDescr=vehCompDesc, isWinner=False, gameMode=gameMode) count = 0 result = [] if not winList or not pointList: _logger.error( 'Failed to get bonus points information! Check server settings are correct for Battle Royale.' ) return result pointList[0] = winList[0] for item in pointList: points, pointsCount = item count += pointsCount if points > 0: result.append(BattleRoyaleTopPoints(count, points)) return result def getChapterConfig(self): return self.__getConfig().finalLevelsInChapter def getChapterLevelInterval(self, chapter): chapterConfig = self.getChapterConfig() if chapter < BattlePassConsts.MINIMAL_CHAPTER_NUMBER or chapter > len( chapterConfig): return (0, 0) fromLevel = 1 if chapter == BattlePassConsts.MINIMAL_CHAPTER_NUMBER else chapterConfig[ chapter - 2] + 1 toLevel = chapterConfig[chapter - 1] return (fromLevel, toLevel) def isSpecialVehicle(self, intCD): return self.__getConfig().isSpecialVehicle(intCD) def getSpecialVehicles(self): return self.__getConfig().getSpecialVehicles() def getPointsDiffForVehicle(self, intCD, gameMode=constants.ARENA_BONUS_TYPE.REGULAR): defaultWinList = self.__getPackedBonusPointsList(gameMode=gameMode) diffWinList = self.__getPackedBonusPointsList(vehTypeCompDescr=intCD, isDiff=True, gameMode=gameMode) if not defaultWinList or not diffWinList: _logger.error( 'Failed to get bonus points information! Check server settings are correct.' ) return PointsDifference(0, 0, 0) diffBlock = diffWinList[0] bonus = diffBlock[0] top = diffBlock[1] textID = getPointsInfoStringID() return PointsDifference(bonus, top, textID) def getVehicleProgression(self, intCD): points = self.__itemsCache.items.battlePass.getPointsForVehicle( intCD, 0) cap = self.__getConfig().vehicleCapacity(intCD) return (points, cap) def getVehicleCapBonus(self, intCD): vehicle = self.__itemsCache.items.getItemByCD(intCD) if vehicle is None: return 0 else: bonus = self.__getConfig().capBonus(vehicle.level) return bonus def getCapacityList(self): capacities = self.__getConfig().capacityList() return enumerate(capacities, 1) def getSeasonTimeLeft(self): return max(0, self.getSeasonFinishTime() - time_utils.getServerUTCTime()) def getFinalOfferTimeLeft(self): return max(0, self.getFinalOfferTime() - time_utils.getServerUTCTime()) def getSeasonStartTime(self): return self.__getConfig().seasonStart def getSeasonFinishTime(self): return self.__getConfig().seasonFinish def hasMaxPointsOnVehicle(self, intCD): currentPoints, limitPoints = self.getVehicleProgression(intCD) return currentPoints >= limitPoints > 0 def isProgressionOnVehiclePossible(self, intCD): cap = self.__getConfig().vehicleCapacity(intCD) return cap > 0 def getSeasonID(self): return self.__itemsCache.items.battlePass.getSeasonID() def getSeasonNum(self): return self.__getConfig().seasonNum def getFinalOfferTime(self): return self.__getConfig().finalOfferTime def getStylesConfig(self): rewards = self.__getConfig().selectedReward return BattlePassAwardsManager.composeBonuses([ rewards ]) if rewards else BattlePassAwardsManager.composeBonuses([]) def getNotChosenRewardCount(self): return sum(( token.startswith(BATTLE_PASS_CHOICE_REWARD_OFFER_GIFT_TOKENS) for token in self.__itemsCache.items.tokens.getTokens().iterkeys() if self.__offersProvider.getOfferByToken(getOfferTokenByGift( token)) is not None)) def hasAnyOfferGiftToken(self): return any( (token.startswith(BATTLE_PASS_CHOICE_REWARD_OFFER_GIFT_TOKENS) for token in self.__itemsCache.items.tokens.getTokens().iterkeys())) def takeRewardForLevel(self, level): chapter = self.getChapterByLevel(level - 1) isBought = self.isBought(chapter=chapter) awardType = BattlePassConsts.REWARD_BOTH if isBought else BattlePassConsts.REWARD_FREE isOfferEnabled = self.isOfferEnabled() bonuses = self.getSingleAward(level, awardType) rewardsToChoose = [] stylesToChoose = [] for bonus in bonuses: bonusName = bonus.getName() if bonusName == BATTLE_PASS_SELECT_BONUS_NAME and isOfferEnabled: for tokenID in bonus.getTokens().iterkeys(): if self.__itemsCache.items.tokens.getToken( tokenID ) is not None and self.__offersProvider.getOfferByToken( getOfferTokenByGift(tokenID)) is not None: rewardsToChoose.append(tokenID) if bonusName == BATTLE_PASS_STYLE_PROGRESS_BONUS_NAME: for tokenID in bonus.getTokens().iterkeys(): if self.__itemsCache.items.tokens.getToken( tokenID) is not None: chapter = bonus.getChapter() if chapter not in stylesToChoose: stylesToChoose.append(chapter) rewardsToChoose.sort( key=lambda x: (int(x.split(':')[-1]), x.split(':')[-2])) self.getRewardLogic().startManualFlow(rewardsToChoose, stylesToChoose) return def takeAllRewards(self): if self.isOfferEnabled(): rewardsToChoose = [ token for token in self.__itemsCache.items.tokens.getTokens().iterkeys() if token.startswith(BATTLE_PASS_CHOICE_REWARD_OFFER_GIFT_TOKENS ) and self.__offersProvider. getOfferByToken(getOfferTokenByGift(token)) is not None ] rewardsToChoose.sort( key=lambda x: (int(x.split(':')[-1]), x.split(':')[-2])) else: rewardsToChoose = [] chapter = self.getCurrentChapter() stylesToChoose = getStylesToChooseUntilChapter(chapter + 1) self.getRewardLogic().startManualFlow(rewardsToChoose, stylesToChoose) return def getChapterStyleProgress(self, chapter): return getMaxAvalable3DStyleProgressInChapter( self.getSeasonID(), chapter, self.__itemsCache.items.tokens.getTokens().keys()) def __stop(self): self.__seasonChangeNotifier.stopNotification() self.__itemsCache.onSyncCompleted -= self.__onSyncCompleted self.__lobbyContext.getServerSettings( ).onServerSettingsChange -= self.__onServerSettingsChange self.__offersProvider.onOffersUpdated -= self.__onOffersUpdated self.__nonSelectedOldTrophyDeviceNotifier.stop() def __getConfig(self): return self.__lobbyContext.getServerSettings().getBattlePassConfig() def __onTokensUpdate(self, diff): for chapter, _ in enumerate(self.getChapterConfig(), BattlePassConsts.MINIMAL_CHAPTER_NUMBER): if getBattlePassPassTokenName(self.getSeasonID(), chapter) in diff: self.onBattlePassIsBought() break if BATTLE_PASS_TOKEN_TROPHY_GIFT_OFFER_2020 in diff or BATTLE_PASS_TOKEN_NEW_DEVICE_GIFT_OFFER_2020 in diff: self.onDeviceSelectChange() def __getTimeUntilStart(self): return max( 0, self.__getConfig().seasonStart - time_utils.getServerUTCTime()) def __getTimeToNotifySeasonChange(self): if not self.isPaused(): if not self.isSeasonStarted(): return self.__getTimeUntilStart() if not self.isSeasonFinished(): return self.getSeasonTimeLeft() def __onNotifySeasonChange(self): self.onSeasonStateChange() def __onServerSettingsChange(self, diff): if BATTLE_PASS_CONFIG_NAME in diff: self.__seasonChangeNotifier.startNotification() newMode = None oldMode = self.__currentMode if 'mode' in diff[BATTLE_PASS_CONFIG_NAME]: newMode = diff[BATTLE_PASS_CONFIG_NAME]['mode'] self.__currentMode = newMode self.onBattlePassSettingsChange(newMode, oldMode) if 'isOffersEnabled' in diff: self.__onOffersUpdated() self.onDeviceSelectChange() return def __onSyncCompleted(self, _, diff): if 'battlePass' in diff: newPoints = diff['battlePass'].get('sumPoints', self.__oldPoints) newLevel = diff['battlePass'].get('level', self.__oldLevel) if newPoints != self.__oldPoints: self.onPointsUpdated() if newLevel != self.__oldLevel: self.onLevelUp() self.__oldPoints = newPoints self.__oldLevel = newLevel def __onOffersUpdated(self): self.__validateOffers() self.onOffersUpdated() def __validateOffers(self): for offer in self.__offersProvider.iAvailableOffers(False): if not offer.token.startswith(BATTLE_PASS_OFFER_TOKEN_PREFIX): continue counts = {gift.giftCount for gift in offer.getAllGifts()} if len(counts) > 1: _logger.error('Wrong bonus count in gifts. Offer token %s', offer.token) @staticmethod def __bonusPointsDiffList(vehTypeCompDescr, config, gameMode): defaultPoints = config.points.get(gameMode, {}) defaultDiff = [0] * len(defaultPoints.get('win', [])) if vehTypeCompDescr in defaultPoints and 'win' in defaultPoints: specialPoints = defaultPoints[vehTypeCompDescr] defaultPoints = defaultPoints['win'] specialPoints = specialPoints['win'] return [a - b for a, b in zip(specialPoints, defaultPoints)] return defaultDiff def __getPackedBonusPointsList( self, vehTypeCompDescr=None, isWinner=True, isDiff=False, gameMode=constants.ARENA_BONUS_TYPE.REGULAR): if isDiff: pointsList = self.__bonusPointsDiffList( vehTypeCompDescr=vehTypeCompDescr, config=self.__getConfig(), gameMode=gameMode) else: pointsList = self.__getConfig().bonusPointsList( vehTypeCompDescr=vehTypeCompDescr, isWinner=isWinner, gameMode=gameMode) return [(key, len(list(group))) for key, group in groupby(pointsList)] @staticmethod def __checkIfRewardIsToken(bonusName, reward): if 'tokens' not in reward: return False bonuses = BattlePassAwardsManager.composeBonuses([reward]) for bonus in bonuses: if bonus.getName() == bonusName: return True return False def __clearFields(self): self.__oldPoints = 0 self.__oldLevel = 0 self.__currentMode = None return
class ProgressionView(ViewImpl): __slots__ = ('__notifier', '__backCallback') _COMMON_SOUND_SPACE = RESOURCE_WELL_SOUND_SPACE __resourceWell = dependency.descriptor(IResourceWellController) def __init__(self, layoutID, backCallback): settings = ViewSettings(R.views.lobby.resource_well.ProgressionView()) settings.flags = ViewFlags.LOBBY_SUB_VIEW settings.model = ProgressionViewModel() self.__backCallback = backCallback super(ProgressionView, self).__init__(settings) self.__notifier = None return @property def viewModel(self): return super(ProgressionView, self).getViewModel() def createToolTipContent(self, event, contentID): if contentID == R.views.lobby.resource_well.tooltips.SerialNumberTooltip(): return SerialNumberTooltip(parentLayout=self.layoutID) if contentID == R.views.lobby.resource_well.tooltips.RefundResourcesTooltip(): return RefundResourcesTooltip() return ProgressTooltip(progress=self.viewModel.getProgression()) if contentID == R.views.lobby.resource_well.tooltips.ProgressTooltip() else super(ProgressionView, self).createToolTipContent(event, contentID) def _onLoading(self, *args, **kwargs): super(ProgressionView, self)._onLoading(*args, **kwargs) self.__resourceWell.startNumberRequesters() self.__notifier = SimpleNotifier(self.__getReminderTimeLeft, self.__updateEventTime) self.__updateModel() ResourceWellMainScreenLogger().onViewOpened(getProgressionState()) def _finalize(self): self.__notifier.stopNotification() self.__resourceWell.stopNumberRequesters() super(ProgressionView, self)._finalize() def _getEvents(self): return ((self.viewModel.onAboutClick, self.__showEventInfo), (self.viewModel.onPreview, self.__showPreview), (self.viewModel.onHangarShow, self.__showHangar), (self.viewModel.onResourcesContribute, self.__contributeResources), (self.viewModel.onResourcesReturn, self.__extractResources), (self.viewModel.onClose, self.__close), (g_playerEvents.onClientUpdated, self.__onClientUpdated), (self.__resourceWell.onNumberRequesterUpdated, self.__onNumberRequesterUpdated), (self.__resourceWell.onEventUpdated, self.__onEventStateUpdated)) def __updateModel(self): with self.viewModel.transaction() as model: self.__fillEventInfo(model=model) self.__fillProgression(model=model) self.__updateEventTime(model=model) self.__fillVehicleName(model=model) self.__fillRewards(model.getRewards()) @replaceNoneKwargsModel def __updateEventTime(self, model=None): model.setEndDate(round(time_utils.makeLocalServerTime(self.__resourceWell.getFinishTime()), -1)) isEventEnding = isEventEndingsSoon(resourceWell=self.__resourceWell) model.setIsEventEndingSoon(isEventEnding) model.setTimeLeft(self.__resourceWell.getFinishTime() - time_utils.getServerUTCTime()) if isEventEnding: self.__notifier.stopNotification() else: self.__notifier.startNotification() @replaceNoneKwargsModel def __fillEventInfo(self, model=None): model.setTopRewardPlayersCount(self.__resourceWell.getRewardLimit(isTop=True)) model.setRegularRewardVehiclesCount(self.__resourceWell.getRewardLimit(isTop=False)) @replaceNoneKwargsModel def __fillProgression(self, model=None): model.setProgressionState(_PROGRESSION_STATE_MAPPING.get(getProgressionState())) currentPoints = self.__resourceWell.getCurrentPoints() maxPoints = self.__resourceWell.getMaxPoints() model.setProgression(_FULL_PROGRESS * currentPoints / (maxPoints or _FULL_PROGRESS)) def __fillVehicleName(self, model=None): vehicle = getVehicleByIntCD(self.__resourceWell.getRewardVehicle()) model.setVehicleName(vehicle.userName) def __fillRewards(self, rewards): rewards.clear() rewards.addViewModel(self.__getRewardModel(isTop=True)) rewards.addViewModel(self.__getRewardModel(isTop=False)) rewards.invalidate() def __getRewardModel(self, isTop): model = RewardModel() model.setIsTop(isTop) model.setIsEnabled(self.__resourceWell.isRewardEnabled(isTop)) model.setVehiclesLeftCount(self.__resourceWell.getRewardLeftCount(isTop)) model.setIsCountAvailable(self.__resourceWell.isRewardCountAvailable(isTop)) fillVehicleInfo(model.vehicleInfo, getVehicleByIntCD(self.__resourceWell.getRewardVehicle())) return model def __close(self): if callable(self.__backCallback): self.__backCallback() else: showHangar() def __showHangar(self): showHangar() self.destroyWindow() def __showPreview(self, args): isStyled = args.get('isStyled', False) style = getRewardStyle(resourceWell=self.__resourceWell) vehicleCD = self.__resourceWell.getRewardVehicle() topPanelData = {'linkage': VEHPREVIEW_CONSTANTS.TOP_PANEL_TABS_LINKAGE, 'tabIDs': PERSONAL_NUMBER_STYLE_TABS, 'currentTabID': TabID.PERSONAL_NUMBER_VEHICLE if isStyled else TabID.BASE_VEHICLE} showResourceWellVehiclePreview(vehicleCD, style, self.__previewCallback, topPanelData) def __previewCallback(self): showResourceWellProgressionWindow(backCallback=self.__backCallback) def __contributeResources(self): showResourcesLoadingWindow(ParentScreens.MAIN_SCREEN) @process def __extractResources(self): yield ResourceWellTakeBackProcessor().request() def __showEventInfo(self): showBrowserOverlayView(GUI_SETTINGS.resourceWell.get('infoPage'), VIEW_ALIAS.RESOURCE_WELL_BROWSER_VIEW) def __onEventStateUpdated(self): if not self.__resourceWell.isActive(): showHangar() else: self.__updateEventTime() def __onEventSettingsUpdated(self): if not self.__resourceWell.isActive(): self.__close() return self.__updateModel() def __getReminderTimeLeft(self): return max(0, self.__resourceWell.getReminderTime() - time_utils.getServerUTCTime()) def __onClientUpdated(self, diff, _): if RESOURCE_WELL_PDATA_KEY in diff: if not self.__resourceWell.isCompleted(): self.__fillProgression() def __onNumberRequesterUpdated(self): with self.viewModel.transaction() as model: self.__fillProgression(model=model) self.__fillRewards(model.getRewards())
class BattlePassController(IBattlePassController): __itemsCache = dependency.descriptor(IItemsCache) __lobbyContext = dependency.descriptor(ILobbyContext) def __init__(self): self.__oldPoints = 0 self.__oldLevel = 0 self.__oldVoteOption = 0 self.__badge = None self.__currentMode = None self.__eventsManager = EventManager() self.__seasonChangeNotifier = SimpleNotifier( self.__getTimeToNotifySeasonChange, self.__onNotifySeasonChange) self.__purchaseUnlockNotifier = SimpleNotifier( self.__getTimeToNotifyPurchaseUnlock, self.__onNotifyUnlock) self.onPointsUpdated = Event(self.__eventsManager) self.onLevelUp = Event(self.__eventsManager) self.onVoted = Event(self.__eventsManager) self.onBattlePassIsBought = Event(self.__eventsManager) self.onSeasonStateChange = Event(self.__eventsManager) self.onUnlimitedPurchaseUnlocked = Event(self.__eventsManager) self.onBattlePassSettingsChange = Event(self.__eventsManager) self.onFinalRewardStateChange = Event(self.__eventsManager) self.__votingRequester = BattlePassVotingRequester(self) self.__finalRewardStateMachine = FinalRewardStateMachine(self) return def init(self): super(BattlePassController, self).init() g_clientUpdateManager.addCallbacks({'tokens': self.__onTokensUpdate}) BattlePassAwardsManager.init() def onLobbyInited(self, event): self.__lobbyContext.getServerSettings( ).onServerSettingsChange += self.__onServerSettingsChange self.__itemsCache.onSyncCompleted += self.__onSyncCompleted self.__seasonChangeNotifier.startNotification() self.__purchaseUnlockNotifier.startNotification() self.__finalRewardStateMachine.init() if self.__currentMode is None: self.__currentMode = self.__getConfig().mode else: self.onBattlePassSettingsChange(self.__getConfig().mode, self.__currentMode) self.__currentMode = self.__getConfig().mode self.__votingRequester.start() return def onAvatarBecomePlayer(self): self.__stop() def onDisconnected(self): self.__finalRewardStateMachine.interruptFlow() self.__stop() self.__clearFields() def fini(self): self.__stop() self.__clearFields() self.__eventsManager.clear() g_clientUpdateManager.removeObjectCallbacks(self) super(BattlePassController, self).fini() def isBought(self, seasonID=None): if seasonID is None: seasonID = self.getSeasonID() token = self.__itemsCache.items.tokens.getTokens().get( getBattlePassPassTokenName(seasonID)) return True if token else False def isEnabled(self): return self.__getConfig().isEnabled() def isActive(self): return self.__getConfig().isActive(time_utils.getServerUTCTime()) def isVisible(self): return self.isSeasonStarted( ) and not self.isDisabled() and not self.isSeasonFinished() def isOffSeasonEnable(self): return (not self.isSeasonStarted() or self.isSeasonFinished()) and not self.isDisabled() def isDisabled(self): return self.__getConfig().isDisabled() def isPaused(self): return self.__getConfig().isPaused() def isPlayerVoted(self): return self.getVoteOption() != 0 def isSeasonStarted(self): return self.__getConfig().seasonStart <= time_utils.getServerUTCTime() def isSeasonFinished(self): return self.__getConfig().seasonFinish <= time_utils.getServerUTCTime() def isSellAnyLevelsUnlocked(self): return self.__getConfig().isSellAnyUnlocked( time_utils.getServerUTCTime()) def isValidBattleType(self, prbEntity): return prbEntity.getEntityType() == constants.ARENA_GUI_TYPE.RANDOM def getMaxLevel(self, isBase=True): return len(self.getLevelsConfig(isBase)) def isRareLevel(self, level, isBase=True): realLevel = min(level, self.getMaxLevel(isBase)) rewardType = BattlePassConsts.REWARD_PAID if isBase else BattlePassConsts.REWARD_POST tags = self.__getConfig().getTags(realLevel, rewardType) return BattlePassConsts.RARE_REWARD_TAG in tags def getVotingRequester(self): return self.__votingRequester def getFinalFlowSM(self): return self.__finalRewardStateMachine def getSplitFinalAwards(self): freeReward = [] paidReward = [] awardsSettings = sorted(self.getFinalRewards().iteritems(), key=itemgetter(0)) voteOption = self.getVoteOption() if voteOption != 0: for vote, config in awardsSettings: shared = BattlePassAwardsManager.composeBonuses( [config.get('shared', {})]) if vote == voteOption: unique = BattlePassAwardsManager.composeBonuses( [config.get('unique', {})]) freeReward.extend(shared) freeReward.extend(unique) paidReward.extend(shared) else: configs = [config for _, config in awardsSettings] if len(configs) != 2: return (freeReward, paidReward) sharedA = BattlePassAwardsManager.composeBonuses( [configs[0].get('shared', {})]) sharedB = BattlePassAwardsManager.composeBonuses( [configs[1].get('shared', {})]) uniqueA = BattlePassAwardsManager.composeBonuses( [configs[0].get('unique', {})]) uniqueB = BattlePassAwardsManager.composeBonuses( [configs[1].get('unique', {})]) for optionA, optionB in zip(sharedA, sharedB): bonus = makeUndefinedBonus(optionA, optionB) freeReward.append(bonus) paidReward.append(bonus) for optionA, optionB in zip(uniqueA, uniqueB): bonus = makeUndefinedBonus(optionA, optionB) freeReward.append(bonus) return (freeReward, paidReward) def getFinalAwardsForPurchaseLevels(self): awards = [] awardsSettings = sorted(self.getFinalRewards().iteritems(), key=itemgetter(0)) configs = [config for _, config in awardsSettings] if len(configs) != 2: return awards awards.extend( BattlePassAwardsManager.composeBonuses( [configs[0].get('shared', {})])) awards.extend( BattlePassAwardsManager.composeBonuses( [configs[1].get('shared', {})])) uniqueA = BattlePassAwardsManager.composeBonuses( [configs[0].get('unique', {})]) uniqueB = BattlePassAwardsManager.composeBonuses( [configs[1].get('unique', {})]) for optionA, optionB in zip(uniqueA, uniqueB): bonus = makeUndefinedBonus(optionA, optionB) awards.append(bonus) return awards def getSingleAward(self, level, awardType=BattlePassConsts.REWARD_FREE, needSort=True): reward = {} if awardType in (BattlePassConsts.REWARD_FREE, BattlePassConsts.REWARD_PAID, BattlePassConsts.REWARD_POST): reward = self.__getConfig().getRewardByType(level, awardType) elif awardType == BattlePassConsts.REWARD_BOTH: rewards = [ self.__getConfig().getFreeReward(level), self.__getConfig().getPaidReward(level) ] return BattlePassAwardsManager.hideInvisible( BattlePassAwardsManager.composeBonuses(rewards)) if needSort: rewards = BattlePassAwardsManager.composeBonuses([reward]) else: rewards = awardsFactory(reward) return BattlePassAwardsManager.hideInvisible(rewards, needSplit=not needSort) def getAwardsInterval(self, fromLevel, toLevel, awardType=BattlePassConsts.REWARD_FREE): result = {} for level in range(fromLevel, toLevel + 1): result[level] = self.getSingleAward(level, awardType, True) return result def getAwardsList(self, awardType=BattlePassConsts.REWARD_FREE): maxLevel = self.getMaxLevel(False if awardType == BattlePassConsts.REWARD_POST else True) return self.getAwardsInterval(1, maxLevel, awardType) def getPackedAwardsInterval(self, fromLevel, toLevel, awardType=BattlePassConsts.REWARD_FREE): result = [] for level in range(fromLevel, toLevel + 1): result.extend(self.getSingleAward(level, awardType, False)) return BattlePassAwardsManager.sortBonuses(result) def getLevelsConfig(self, isBase=True): return self.__getConfig().basePoints if isBase else self.__getConfig( ).postPoints def getFinalRewards(self): return self.__getConfig().finalReward def getFreeFinalRewardDict(self): return self.__getConfig().getRewardByType(self.getMaxLevel(), BattlePassConsts.REWARD_FREE) def getCurrentPoints(self, aligned=False): points = self.__itemsCache.items.battlePass.getPoints() return self.__getConfig().alignedPointsFromSumPoints( points) if aligned else points def getMaxPoints(self, isBase=True): return self.__getConfig( ).maxBasePoints if isBase else self.__getConfig().maxPostPoints def getCurrentLevel(self): return self.__itemsCache.items.battlePass.getCurrentLevel() def getState(self): return self.__itemsCache.items.battlePass.getState() def getMaxSoldLevelsBeforeUnlock(self): return self.__getConfig().maxSoldLevelsBeforeUnlock def getBoughtLevels(self): return self.__itemsCache.items.battlePass.getBoughtLevels() def getVoteOption(self): return self.__itemsCache.items.battlePass.getVoteOption() def getPrevSeasonsStats(self): packedStats = self.__itemsCache.items.battlePass.getPackedStats() if not packedStats: return None else: unpackStats, _ = BattlePassStatsCommon.unpackAllSeasonStats( packedStats) return unpackStats def getLastFinishedSeasonStats(self): allSeasonStats = self.getPrevSeasonsStats() if not allSeasonStats: seasons = sorted(self.getSeasonsHistory().keys(), reverse=True) return BattlePassStatsCommon.makeSeasonStats( first(seasons), {}, BattlePassStatsCommon.initialSeasonStatsData()) return allSeasonStats[-1] def getSeasonsHistory(self): return self.__getConfig().seasonsHistory def getAlternativeVoteOption(self): voteOption = self.getVoteOption() if voteOption == 0: return 0 voteOptions = self.getFinalRewards().keys() alternativeOption = findFirst(lambda option: option != voteOption, voteOptions, 0) return alternativeOption def getLevelPoints(self, level, isBase=True): levelsConfig = self.getLevelsConfig(isBase) return levelsConfig[ 0] if level <= 0 else levelsConfig[level] - levelsConfig[level - 1] def getLevelProgression(self): if self.isDisabled(): return (0, 0) state = self.getState() if state == BattlePassState.COMPLETED: levelsConfig = self.getLevelsConfig(False) points = levelsConfig[-1] - levelsConfig[-2] return (points, points) level = self.getCurrentLevel() points = self.getCurrentPoints(aligned=True) levelsConfig = self.getLevelsConfig(state == BattlePassState.BASE) return getLevelProgression(level, points, levelsConfig) def getLevelByPoints(self, points): if points >= self.__getConfig().maxPostPoints + self.__getConfig( ).maxBasePoints: state = BattlePassState.COMPLETED elif points >= self.__getConfig().maxBasePoints: state = BattlePassState.POST else: state = BattlePassState.BASE if state == BattlePassState.COMPLETED: level = self.getMaxLevel(isBase=False) else: alignedPoints = points - self.__getConfig( ).maxBasePoints if state == BattlePassState.POST else points levelsConfig = self.getLevelsConfig( isBase=state == BattlePassState.BASE) level = getLevel(curPoints=alignedPoints, levelPoints=levelsConfig) return (state, level) def getProgressionByPoints(self, points, state, level): if state == BattlePassState.COMPLETED: levelsConfig = self.getLevelsConfig(isBase=False) levelPoints = fullLevelPoints = levelsConfig[-1] - levelsConfig[-2] else: alignedPoints = points - self.__getConfig( ).maxBasePoints if state == BattlePassState.POST else points levelsConfig = self.getLevelsConfig( isBase=state == BattlePassState.BASE) levelPoints, fullLevelPoints = getLevelProgression( level, alignedPoints, levelsConfig) return (levelPoints, fullLevelPoints) def getPerBattlePoints(self, vehCompDesc=None): winList = self.__getPackedBonusPointsList(vehTypeCompDescr=vehCompDesc) lostList = self.__getPackedBonusPointsList( vehTypeCompDescr=vehCompDesc, isWinner=False) count = 0 result = [] for winInfo, lostInfo in zip(winList, lostList): pointsWin, pointsCount = winInfo pointsLost, _ = lostInfo count += pointsCount if pointsWin > 0: item = TopPoints(count, pointsWin, pointsLost) result.append(item) return result def getBadgeData(self): if self.__badge is None: self.__extractBadgeInfo() return self.__badge def isSpecialVehicle(self, intCD): return self.__getConfig().isSpecialVehicle(intCD) def getSpecialVehicles(self): return self.__getConfig().getSpecialVehicles() def getPointsDiffForVehicle(self, intCD): defaultWinList = self.__getPackedBonusPointsList() diffWinList = self.__getPackedBonusPointsList(vehTypeCompDescr=intCD, isDiff=True) if not defaultWinList or not diffWinList: _logger.error( 'Failed to get bonus points information! Check server settings are correct.' ) return PointsDifference(0, 0, 0) defaultBlock = defaultWinList[-1] diffBlock = diffWinList[0] bonus = diffBlock[0] top = 0 if diffBlock[1] == BattlePassConfig.MAX_RANKS - defaultBlock[ 1] else diffBlock[1] textID = getPointsInfoStringID(top != 0) return PointsDifference(bonus, top, textID) def getVehicleProgression(self, intCD): points = self.__itemsCache.items.battlePass.getPointsForVehicle( intCD, 0) cap = self.__getConfig().vehicleCapacity(intCD) return (points, cap) def getVehicleCapBonus(self, intCD): vehicle = self.__itemsCache.items.getItemByCD(intCD) if vehicle is None: return 0 else: bonus = self.__getConfig().capBonus(vehicle.level) return bonus def getCapacityList(self): capacities = self.__getConfig().capacityList() return enumerate(capacities, 1) def getSeasonTimeLeft(self): return max(0, self.getSeasonFinishTime() - time_utils.getServerUTCTime()) def getSellAnyLevelsUnlockTimeLeft(self): return max( 0, self.getSellAnyLevelsUnlockTime() - time_utils.getServerUTCTime()) def getFinalOfferTimeLeft(self): return max(0, self.getFinalOfferTime() - time_utils.getServerUTCTime()) def getSeasonStartTime(self): return self.__getConfig().seasonStart def getSeasonFinishTime(self): return self.__getConfig().seasonFinish def getSellAnyLevelsUnlockTime(self): return self.__getConfig().sellAnyLevelsUnlockTime def hasMaxPointsOnVehicle(self, intCD): currentPoints, limitPoints = self.getVehicleProgression(intCD) return currentPoints >= limitPoints > 0 def isProgressionOnVehiclePossible(self, intCD): cap = self.__getConfig().vehicleCapacity(intCD) return cap > 0 def canPlayerParticipate(self): criteria = REQ_CRITERIA.INVENTORY criteria |= ~REQ_CRITERIA.VEHICLE.EPIC_BATTLE criteria |= REQ_CRITERIA.CUSTOM( lambda veh: not self.hasMaxPointsOnVehicle(veh.intCD)) criteria |= REQ_CRITERIA.CUSTOM( lambda veh: self.isProgressionOnVehiclePossible(veh.intCD)) availableVehiclesToProgression = self.__itemsCache.items.getVehicles( criteria) return len(availableVehiclesToProgression) > 0 def getSeasonID(self): return self.__itemsCache.items.battlePass.getSeasonID() def getFinalOfferTime(self): return self.__getConfig().finalOfferTime def __stop(self): self.__seasonChangeNotifier.stopNotification() self.__purchaseUnlockNotifier.stopNotification() self.__itemsCache.onSyncCompleted -= self.__onSyncCompleted self.__lobbyContext.getServerSettings( ).onServerSettingsChange -= self.__onServerSettingsChange self.__votingRequester.stop() def __getFrontierStep(self): return self.__getConfig().postPoints def __getConfig(self): return self.__lobbyContext.getServerSettings().getBattlePassConfig() def __onTokensUpdate(self, diff): if getBattlePassPassTokenName(self.getSeasonID()) in diff: self.onBattlePassIsBought() def __getTimeUntilStart(self): return max( 0, self.__getConfig().seasonStart - time_utils.getServerUTCTime()) def __getTimeToNotifySeasonChange(self): if self.isEnabled() or self.isPaused(): if not self.isSeasonStarted(): return self.__getTimeUntilStart() if not self.isSeasonFinished(): return self.getSeasonTimeLeft() def __onNotifySeasonChange(self): self.onSeasonStateChange() def __getTimeToNotifyPurchaseUnlock(self): return self.getSellAnyLevelsUnlockTimeLeft( ) if self.isEnabled() or self.isPaused() else 0 def __onNotifyUnlock(self): self.onUnlimitedPurchaseUnlocked() def __onServerSettingsChange(self, diff): if BATTLE_PASS_CONFIG_NAME in diff: self.__seasonChangeNotifier.startNotification() self.__purchaseUnlockNotifier.startNotification() newMode = None oldMode = self.__currentMode if 'mode' in diff[BATTLE_PASS_CONFIG_NAME]: newMode = diff[BATTLE_PASS_CONFIG_NAME]['mode'] self.__currentMode = newMode self.__extractBadgeInfo() self.onBattlePassSettingsChange(newMode, oldMode) return def __onSyncCompleted(self, _, diff): if 'battlePass' in diff: newPoints = diff['battlePass'].get('sumPoints', self.__oldPoints) newLevel = diff['battlePass'].get('level', self.__oldLevel) newVoteOption = diff['battlePass'].get('voteOption', self.__oldVoteOption) if newPoints != self.__oldPoints: self.onPointsUpdated() if newLevel != self.__oldLevel: self.onLevelUp() if newVoteOption != self.__oldVoteOption: self.onVoted() self.__oldPoints = newPoints self.__oldLevel = newLevel self.__oldVoteOption = newVoteOption def __getPackedBonusPointsList(self, vehTypeCompDescr=None, isWinner=True, isDiff=False): if isDiff: pointsList = self.__getConfig().bonusPointsDiffList( vehTypeCompDescr=vehTypeCompDescr) else: pointsList = self.__getConfig().bonusPointsList( vehTypeCompDescr=vehTypeCompDescr, isWinner=isWinner) return [(key, len(list(group))) for key, group in groupby(pointsList)] def __extractBadgeInfo(self): config = self.__getConfig() for level in range(1, self.getMaxLevel() + 1): if self.__processRewardIsBadge(config.getFreeReward(level)): return for level in range(1, self.getMaxLevel(False) + 1): if self.__processRewardIsBadge(config.getPostReward(level)): return self.__badge = None return def __processRewardIsBadge(self, reward): if 'dossier' not in reward: return False bonuses = BattlePassAwardsManager.composeBonuses([reward]) for bonus in bonuses: if bonus.getName() != 'dossier': continue if bonus.getBadges(): self.__badge = bonus return True return False def __clearFields(self): self.__oldPoints = 0 self.__oldLevel = 0 self.__oldVoteOption = 0 self.__badge = None self.__currentMode = None return