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 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 LowTierMMController(ILowTierMMController): __eventsCache = dependency.descriptor(IEventsCache) def __init__(self): super(LowTierMMController, self).__init__() self.onEventStateChanged = Event.Event() self.__isEventActive = False self.__dateFinish = None self.__notifier = None return def fini(self): self.__clear() self.onEventStateChanged.clear() self.__clearNotifier() def isEnabled(self): return self.__isEventActive def getDateFinish(self): return self.__dateFinish def onLobbyInited(self, event): self.__eventsCache.onSyncCompleted += self.__update self.__update() def onAvatarBecomePlayer(self): self.__clear() self.__clearNotifier() def onDisconnected(self): self.__clear() self.__clearNotifier() def __getTimeDelta(self): return self.__dateFinish - time_utils.getServerUTCTime() def __clear(self): self.__isEventActive = False self.__dateFinish = None self.__eventsCache.onSyncCompleted -= self.__update return def __clearNotifier(self): if self.__notifier: self.__notifier.stopNotification() self.__notifier.clear() self.__notifier = None return def __update(self): actions = self.__eventsCache.getActions() eventState = self.__getEventParams(actions, _EVENT_STATE_NAME) try: dateFinishDT = datetime.strptime(eventState.strip(), FORMAT_DATE) self.__dateFinish = calendar.timegm(dateFinishDT.timetuple()) except (AttributeError, TypeError): self.__updateEvent(False) self.__dateFinish = None return currtime = time_utils.getServerUTCTime() eventState = self.__dateFinish > currtime self.__updateEvent(eventState) self.__clearNotifier() if eventState: self.__notifier = SimpleNotifier(self.__getTimeDelta, self.__update) self.__notifier.startNotification() else: self.__dateFinish = None return @staticmethod def __getEventParams(actions, eventName): for action in actions.itervalues(): steps = action.getData()['steps'] if steps is None: continue for step in steps: if step.get('name') != eventName: continue return step.get('params').get('date') return def __updateEvent(self, eventState): if self.__isEventActive != eventState: self.__isEventActive = eventState setEnabledMMEvent(self.__isEventActive) self.onEventStateChanged()
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 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 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