Пример #1
0
class _PreBattleDispatcher(ListenersCollection):
    """
    Dispatcher is a class that handles all actions from player related to
    prebattles: select, join, create, etc. Also dispatcher itself is a listeners
    collection that is used for global listening of prebattle events.
    """
    gameSession = dependency.descriptor(IGameSessionController)
    rentals = dependency.descriptor(IRentalsController)
    igrCtrl = dependency.descriptor(IIGRController)
    falloutCtrl = dependency.descriptor(IFalloutController)
    eventsCache = dependency.descriptor(IEventsCache)

    def __init__(self):
        """
        In init we're setting default request context, factories composite
        default entity and supported listeners class.
        """
        super(_PreBattleDispatcher, self).__init__()
        self.__requestCtx = PrbCtrlRequestCtx()
        self.__factories = ControlFactoryComposite()
        self.__entity = NotSupportedEntity()
        self.__prevEntity = NotSupportedEntity()
        self._setListenerClass(IGlobalListener)

    def __del__(self):
        """
        Just a mark for logs that shows us when dispatcher was deleted.
        """
        LOG_DEBUG('_PreBattleDispatcher deleted')

    def start(self):
        """
        Start is called when dispatcher should start its job and process events.
        """
        g_eventDispatcher.init(self)
        result = self.__setDefault()
        self.__startListening()
        initDevFunctional()
        if result & FUNCTIONAL_FLAG.LOAD_PAGE == 0:
            g_eventDispatcher.loadHangar()
        if GUI_SETTINGS.specPrebatlesVisible and not prb_getters.areSpecBattlesHidden(
        ):
            g_eventDispatcher.addSpecBattlesToCarousel()

    def stop(self):
        """
        Is called when its time to stop dispatchers work.
        """
        self.__stopListening()
        finiDevFunctional()
        self.__clear(woEvents=True)
        g_eventDispatcher.fini()

    def getEntity(self):
        """
        Getter for current entity.
        Returns:
            current prebattle entity
        """
        return self.__entity

    def getControlFactories(self):
        """
        Getter for factories composite.
        Returns:
            control factories
        """
        return self.__factories

    def getFunctionalState(self):
        """
        Gets current functional state.
        Returns:
            current functional state
        """
        factory = self.__factories.get(self.__entity.getCtrlType())
        if factory is not None:
            return factory.createStateEntity(self.__entity)
        else:
            return FunctionalState()

    @async
    @process
    def create(self, ctx, callback=None):
        """
        Asynchronous method for prebattle creation. Using given context its
        creates entry point via factories and uses it to create new prebattle.
        Current entity will be destroyed.
        Args:
            ctx: creation context
            callback: request callback
        """
        if ctx.getRequestType() != _RQ_TYPE.CREATE:
            LOG_ERROR('Invalid context to create prebattle/unit', ctx)
            if callback is not None:
                callback(False)
            return
        else:
            entry = self.__factories.createEntry(ctx)
            if entry is None:
                LOG_ERROR('Entry not found', ctx)
                if callback is not None:
                    callback(False)
                return
            if not entry.canCreate():
                if callback is not None:
                    callback(False)
                return
            ctx.addFlags(entry.getFunctionalFlags() | FUNCTIONAL_FLAG.SWITCH)
            if not self.__validateJoinOp(ctx):
                if callback is not None:
                    callback(False)
                return
            result = yield self.unlock(ctx)
            if not result:
                if callback is not None:
                    callback(False)
                return
            ctx.setForced(True)
            LOG_DEBUG('Request to create', ctx)
            self.__requestCtx = ctx
            entry.create(ctx, callback=callback)
            return

    @async
    @process
    def join(self, ctx, callback=None):
        """
        Asynchronous method for prebattle joining. Using given context its
        creates entry point via factories and uses it to join another prebattle.
        Current entity will be destroyed.
        Args:
            ctx: join context
            callback: request callback
        """
        if ctx.getRequestType() != _RQ_TYPE.JOIN:
            LOG_ERROR('Invalid context to join prebattle/unit', ctx)
            if callback is not None:
                callback(False)
            return
        else:
            entry = self.__factories.createEntry(ctx)
            if entry is None:
                LOG_ERROR('Entry not found', ctx)
                if callback is not None:
                    callback(False)
                return
            if not entry.canJoin():
                if callback is not None:
                    callback(False)
                return
            ctx.addFlags(entry.getFunctionalFlags() | FUNCTIONAL_FLAG.SWITCH)
            if not self.__validateJoinOp(ctx):
                if callback is not None:
                    callback(False)
                return
            result = yield self.unlock(ctx)
            if not result:
                if callback is not None:
                    callback(False)
                return
            ctx.setForced(True)
            LOG_DEBUG('Request to join', ctx)
            self.__requestCtx = ctx
            entry.join(ctx, callback=callback)
            return

    @async
    @process
    def leave(self, ctx, callback=None):
        """
        Asynchronous method for prebattle leaving. Using given context its
        leaves current entity.
        Args:
            ctx: leave context
            callback: request callback
        """
        if ctx.getRequestType() != _RQ_TYPE.LEAVE:
            LOG_ERROR('Invalid context to leave prebattle/unit', ctx)
            if callback is not None:
                callback(False)
            return
        elif self.__requestCtx.isProcessing():
            LOG_ERROR('Request is processing', self.__requestCtx)
            if callback is not None:
                callback(False)
            return
        else:
            entity = self.__entity
            meta = entity.getConfirmDialogMeta(ctx)
            if meta:
                result = yield DialogsInterface.showDialog(meta)
                if not result:
                    if callback is not None:
                        callback(False)
                    return
            if not entity.isActive():
                if callback is not None:
                    callback(False)
                return
            ctrlType = ctx.getCtrlType()
            if entity.hasLockedState():
                entityType = entity.getEntityType()
                SystemMessages.pushI18nMessage(
                    messages.getLeaveDisabledMessage(ctrlType, entityType),
                    type=SystemMessages.SM_TYPE.Warning)
                if callback is not None:
                    callback(False)
                return
            LOG_DEBUG('Request to leave formation', ctx)
            self.__requestCtx = ctx
            entity.leave(ctx, callback=callback)
            return

    @async
    @process
    def unlock(self, unlockCtx, callback=None):
        """
        Asynchronous method to leave from prebattle if player is in formation
        and shows confirmation dialog.
        Args:
            unlockCtx: unlock context
            callback: request callback
        """
        if isinstance(self.__entity, NotSupportedEntity):
            if callback is not None:
                callback(True)
            return
        else:
            state = self.getFunctionalState()
            ctrlType = state.ctrlTypeID
            factory = self.__factories.get(ctrlType)
            if factory is None:
                LOG_ERROR('Factory is not found', state)
                if callback is not None:
                    callback(True)
                return
            ctx = factory.createLeaveCtx(unlockCtx.getFlags(),
                                         self.__entity.getEntityType())
            result = yield self.leave(ctx)
            if callback is not None:
                callback(result)
            return

    @async
    @process
    def select(self, entry, callback=None):
        """
        Asynchronous method to select prebattle mode and leave current mode if given entry
        is not just visual.
        Args:
            entry: newly selected entry point
            callback: request callback
        """
        ctx = entry.makeDefCtx()
        ctx.addFlags(entry.getModeFlags() & FUNCTIONAL_FLAG.LOAD_PAGE
                     | FUNCTIONAL_FLAG.SWITCH)
        if not self.__validateJoinOp(ctx):
            if callback is not None:
                callback(False)
            return
        else:
            if entry.isVisualOnly():
                result = True
            else:
                result = yield self.unlock(ctx)
            if not result:
                if callback is not None:
                    callback(False)
                return
            ctx.setForced(True)
            LOG_DEBUG('Request to select', ctx)
            self.__requestCtx = ctx
            entry.select(ctx, callback=callback)
            return

    @async
    def sendPrbRequest(self, ctx, callback=None):
        """
        Asynchronous method for send request to prebattle.
        Args:
            ctx: request context
            callback: request callback
        """
        self.__entity.request(ctx, callback=callback)

    def getPlayerInfo(self):
        """
        Gets information of player (is creator, is ready, etc.) in current active entity.
        Returns:
            current player info
        """
        factory = self.__factories.get(self.__entity.getCtrlType())
        if factory is not None:
            return factory.createPlayerInfo(self.__entity)
        else:
            return PlayerDecorator()

    def doAction(self, action=None):
        """
        Processes action that comes from GUI by current entity.
        Args:
            action: given player's action
        Returns:
            was this action successful
        """
        if not g_currentVehicle.isPresent():
            SystemMessages.pushMessage(messages.getInvalidVehicleMessage(
                PREBATTLE_RESTRICTION.VEHICLE_NOT_PRESENT),
                                       type=SystemMessages.SM_TYPE.Error)
            return False
        LOG_DEBUG('Do GUI action', action)
        return self.__entity.doAction(action)

    @async
    @process
    def doSelectAction(self, action, callback=None):
        """
        Processes action that comes from GUI to change to another mode.
        Args:
            action: given player's select action
            callback: request callback
        """
        selectResult = self.__entity.doSelectAction(action)
        if selectResult.isProcessed:
            result = True
            if selectResult.newEntry is not None:
                result = yield self.select(selectResult.newEntry)
            if callback is not None:
                callback(result)
            return
        else:
            entry = self.__factories.createEntryByAction(action)
            if entry is not None:
                result = yield self.select(entry)
                if callback is not None:
                    callback(result)
                return
            if callback is not None:
                callback(False)
            return

    @async
    @process
    def doLeaveAction(self, action, callback=None):
        """
        Processes action that comes from GUI to leave current mode.
        Args:
            action: given player's leave action
            callback: callback function or None
        """
        factory = self.__factories.get(self.__entity.getCtrlType())
        if factory is None:
            LOG_ERROR('Factory is not found', self.__entity)
            if callback is not None:
                callback(True)
            return
        else:
            flags = FUNCTIONAL_FLAG.UNDEFINED
            if action.isExit:
                flags = FUNCTIONAL_FLAG.EXIT
            elif self.__entity.canKeepMode():
                flags = self.__entity.getModeFlags()
            ctx = factory.createLeaveCtx(
                flags, entityType=self.__entity.getEntityType())
            if self.__entity.isInCoolDown(ctx.getRequestType()):
                if callback is not None:
                    callback(True)
                return
            self.__entity.setCoolDown(ctx.getRequestType(), ctx.getCooldown())
            result = yield self.leave(ctx)
            if callback is not None:
                callback(result)
            return

    def getGUIPermissions(self):
        """
        Gets available action in GUI for current player.
        Returns:
            current GUI permissions
        """
        return self.__entity.getPermissions()

    def isRequestInProcess(self):
        """
        Is current request in process.
        Returns:
            is request in process now
        """
        return self.__requestCtx.isProcessing()

    def restorePrevious(self):
        """
        Trying to set current entity to previous.
        Returns:
            initialization result as flags
        """
        return self.__setEntity(
            CreatePrbEntityCtx(self.__prevEntity.getCtrlType(),
                               self.__prevEntity.getEntityType(),
                               flags=self.__prevEntity.getFunctionalFlags()))

    def pe_onArenaCreated(self):
        """
        Player event listener for arena creation. Updates UI.
        """
        if self.__entity.hasLockedState():
            g_eventDispatcher.updateUI()

    def pe_onArenaJoinFailure(self, errorCode, errorStr):
        """
        Player event listener for arena join failure. Pushes system message.
        Args:
            errorCode: join error code
            errorStr: join error message
        """
        SystemMessages.pushMessage(messages.getJoinFailureMessage(errorCode),
                                   type=SystemMessages.SM_TYPE.Error)

    def pe_onKickedFromArena(self, reasonCode):
        """
        Player event listener for arena kick. Resets state and pushes system message.
        Args:
            reasonCode: kick reason code
        """
        self.__entity.resetPlayerState()
        SystemMessages.pushMessage(messages.getKickReasonMessage(reasonCode),
                                   type=SystemMessages.SM_TYPE.Error)

    def pe_onPrebattleAutoInvitesChanged(self):
        """
        Player event listener for autoinvites state. Controls chat tab visibility of spec battles
        and updates UI.
        """
        if GUI_SETTINGS.specPrebatlesVisible:
            isHidden = prb_getters.areSpecBattlesHidden()
            if isHidden:
                g_eventDispatcher.removeSpecBattlesFromCarousel()
            else:
                g_eventDispatcher.addSpecBattlesToCarousel()
        g_eventDispatcher.updateUI()

    def pe_onPrebattleInviteError(self, inviteID, errorCode, errorStr):
        """
        Player event listener for prebattle invitation failed. Resets current entity to default.
        """
        self.__unsetEntity()
        self.__setDefault()

    def pe_onPrebattleJoined(self):
        """
        Player event listener for prebattle join. Sets entity to proper legacy or
        resets to default.
        """
        if prb_getters.getClientPrebattle() is not None:
            self.__setLegacy(self.__requestCtx.getFlags())
        else:
            LOG_ERROR('ClientPrebattle is not defined')
            self.__setDefault()
            g_eventDispatcher.loadHangar()
        return

    def pe_onPrebattleJoinFailure(self, errorCode):
        """
        Player event listener for prebattle join filure. Pushes system message and
        resets current entity to default.
        Args:
            errorCode: join error code
        """
        SystemMessages.pushMessage(messages.getJoinFailureMessage(errorCode),
                                   type=SystemMessages.SM_TYPE.Error)
        self.__setDefault()
        g_eventDispatcher.loadHangar()

    def pe_onPrebattleLeft(self):
        """
        Player event listener for prebattle left. Tries to keep current mode or
        just unsets current entity.
        """
        flags = self.__requestCtx.getFlags()
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            prbType = 0
            if flags & FUNCTIONAL_FLAG.EXIT == 0:
                prbType = self.__entity.getEntityType()
            self.__unsetEntity(self.__requestCtx)
            self.__setLegacy(flags=flags, prbType=prbType)
        else:
            self.__unsetEntity(self.__requestCtx)

    def pe_onKickedFromPrebattle(self, kickReason):
        """
        Player event listener for prebattle kick. Resets current entity to default.
        """
        self.__unsetEntity()
        self.__setDefault()

    def ctrl_onLegacyIntroModeJoined(self, prbType):
        """
        Prebattle control events listener for legacy intro join. Sets new legacy entity.
        Args:
            prbType: joined prebattle type
        """
        self.__setLegacy(flags=self.__requestCtx.getFlags(), prbType=prbType)

    def ctrl_onLegacyIntroModeLeft(self):
        """
        Prebattle control events listener for legacy intro leave. Unsets current legacy entity
        and inits default state if it is not switch.
        """
        flags = self.__requestCtx.getFlags()
        self.__unsetEntity(self.__requestCtx)
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            self.__setDefault()

    def ctrl_onLegacyInited(self):
        """
        Prebattle control events listener for legacy init. Sets new legacy entity.
        """
        self.__setLegacy(flags=self.__requestCtx.getFlags())

    def ctrl_onUnitIntroModeJoined(self, prbType, flags):
        """
        Prebattle control events listener for unit intro mode join. Sets new unit entity.
        Args:
            prbType: intro prebattle type
            flags: functional flags
        """
        self.__setUnit(flags=flags, prbType=prbType)

    def ctrl_onUnitBrowserModeLeft(self, prbType):
        """
        Prebattle control events listener for unit browser mode leave. Unsets current unit entity
        and tries to init intro mode if it is not switch.
        Args:
            prbType: intro prebattle type
        """
        flags = self.__requestCtx.getFlags()
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            prbType = 0
            if flags & FUNCTIONAL_FLAG.EXIT == 0:
                unitEntity = self.__entity
                if unitEntity.canKeepMode():
                    prbType = unitEntity.getIntroType()
                    flags |= unitEntity.getModeFlags()
            self.__unsetEntity(self.__requestCtx)
            self.__setUnit(flags=flags, prbType=prbType)
        else:
            self.__unsetEntity(self.__requestCtx)

    def ctrl_onUnitIntroModeLeft(self):
        """
        Prebattle control events listener for unit intro leave. Unsets current unit entity
        and inits default state if it is not switch.
        """
        flags = self.__requestCtx.getFlags()
        self.__unsetEntity(self.__requestCtx)
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            self.__setDefault()

    def unitMgr_onUnitJoined(self, unitMgrID, prbType):
        """
        Unit manager event listener for unit join. Sets unit entity if we're not already
        joined to it.
        Args:
            unitMgrID: unit manager identifier
            prbType: unit prebattle type
        """
        entity = self.__entity
        ctx = JoinUnitCtx(unitMgrID, prbType)
        if entity.isPlayerJoined(ctx):
            entity.rejoin()
        else:
            self.__setUnit(flags=self.__requestCtx.getFlags(),
                           prbType=self.__requestCtx.getEntityType())

    def unitMgr_onUnitLeft(self, unitMgrID):
        """
        Unit manager listener for unit left. Tries to keep current mode or
        just unsets current entity.
        Args:
            unitMgrID: unit manager identifier
        """
        flags = self.__requestCtx.getFlags()
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            prbType = 0
            if flags & FUNCTIONAL_FLAG.EXIT == 0:
                unitEntity = self.__entity
                if unitEntity.canKeepMode():
                    prbType = unitEntity.getEntityType()
                    flags |= unitEntity.getModeFlags(
                    ) | FUNCTIONAL_FLAG.UNIT_BROWSER
            self.__unsetEntity(self.__requestCtx)
            self.__setUnit(flags=flags, prbType=prbType)
        else:
            self.__unsetEntity(self.__requestCtx)

    def unitMgr_onUnitRestored(self, unitMgrID):
        """
        Unit manager event listener for unit restoration.
        Args:
            unitMgrID: unit manager identifier
        """
        self.__entity.restore()

    def unitMgr_onUnitErrorReceived(self, requestID, unitMgrID, errorCode,
                                    errorString):
        """
        Unit manager event listener for unit request error. Pushes system message.
        Args:
            requestID: request identifier
            unitMgrID: unit manager identifier
            errorCode: request error code
            errorString: request error message
        """
        if errorCode not in IGNORED_UNIT_MGR_ERRORS:
            msgType, msgBody = messages.getUnitMessage(errorCode, errorString)
            SystemMessages.pushMessage(msgBody, type=msgType)
            self.__requestCtx.stopProcessing()
        if errorCode in ENTER_UNIT_MGR_ERRORS:
            self.restorePrevious()

    def unitBrowser_onErrorReceived(self, errorCode, errorString):
        """
        Unit browser event listener for request error. Pushes system message and resets current
        entity to default.
        Args:
            errorCode: request error code
            errorString: request error message
        """
        if errorCode not in IGNORED_UNIT_BROWSER_ERRORS:
            msgType, msgBody = messages.getUnitBrowserMessage(
                errorCode, errorString)
            SystemMessages.pushMessage(msgBody, type=msgType)
            self.__unsetEntity()
            self.__setDefault()

    def ctrl_onPreQueueJoined(self, queueType):
        """
        Prebattle control events for pre queue join. Sets pre queue entity.
        Args:
            queueType: queue type
        """
        self.__setPreQueue(flags=self.__requestCtx.getFlags(),
                           queueType=queueType)

    def ctrl_onPreQueueJoinFailure(self, errorCode):
        """
        Player event listener for prequeue join filure. Resets current entity to default.
        Args:
            errorCode: join error code
        """
        self.__setDefault()

    def ctrl_onPreQueueLeft(self):
        """
        Prebattle control events for pre queue leave. Unsets current unit entity
        and inits default state if it is not switch.
        """
        flags = self.__requestCtx.getFlags()
        self.__unsetEntity(self.__requestCtx)
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            self.__setDefault()

    def gs_onTillBanNotification(self, isPlayTimeBan, timeTillBlock):
        """
        Game session listener for ban notification. Resets current entity to default.
        Args:
            isPlayTimeBan: is ban for play time
            timeTillBlock: time when block will be activated
        """
        if prb_getters.isParentControlActivated():
            self.__entity.resetPlayerState()
            key = '#system_messages:gameSessionControl/korea/{0:>s}'
            if isPlayTimeBan:
                SystemMessages.pushI18nMessage(
                    key.format('playTimeNotification'),
                    timeTillBlock,
                    type=SystemMessages.SM_TYPE.Warning)
            else:
                notifyStartTime, blockTime = self.gameSession.getCurfewBlockTime(
                )
                formatter = lambda t: time.strftime('%H:%M', time.localtime(t))
                SystemMessages.pushI18nMessage(
                    key.format('midnightNotification'),
                    type=SystemMessages.SM_TYPE.Warning,
                    preBlockTime=formatter(notifyStartTime),
                    blockTime=formatter(blockTime))

    def rc_onRentChange(self, vehicles):
        """
        Rental listener for vehicles state update. Resets current player's state.
        Args:
            vehicles: list of affected vehicle intCDs
        """
        if g_currentVehicle.isPresent(
        ) and g_currentVehicle.item.intCD in vehicles and g_currentVehicle.isDisabledInRent(
        ) and g_currentVehicle.isInPrebattle():
            self.__entity.resetPlayerState()

    def igr_onRoomChange(self, roomType, xpFactor):
        """
        IGR listener for room state. Resets current player's state when he is in premium IGR,
        joined some prebattle and this room is no more premium.
        Args:
            roomType: new IGR room type
            xpFactor: xp boost factor
        """
        if roomType != IGR_TYPE.PREMIUM:
            if g_currentVehicle.isPremiumIGR(
            ) and g_currentVehicle.isInPrebattle():
                self.__entity.resetPlayerState()

    def __startListening(self):
        """
        Subscribes to player and system events.
        """
        g_playerEvents.onPrebattleJoined += self.pe_onPrebattleJoined
        g_playerEvents.onPrebattleJoinFailure += self.pe_onPrebattleJoinFailure
        g_playerEvents.onPrebattleLeft += self.pe_onPrebattleLeft
        g_playerEvents.onKickedFromPrebattle += self.pe_onKickedFromPrebattle
        g_playerEvents.onArenaCreated += self.pe_onArenaCreated
        g_playerEvents.onArenaJoinFailure += self.pe_onArenaJoinFailure
        g_playerEvents.onKickedFromArena += self.pe_onKickedFromArena
        g_playerEvents.onPrebattleAutoInvitesChanged += self.pe_onPrebattleAutoInvitesChanged
        g_playerEvents.onPrebattleInvitationsError += self.pe_onPrebattleInviteError
        if self.gameSession.lastBanMsg is not None:
            self.gs_onTillBanNotification(*self.gameSession.lastBanMsg)
        self.gameSession.onTimeTillBan += self.gs_onTillBanNotification
        self.rentals.onRentChangeNotify += self.rc_onRentChange
        self.igrCtrl.onIgrTypeChanged += self.igr_onRoomChange
        unitMgr = prb_getters.getClientUnitMgr()
        if unitMgr:
            unitMgr.onUnitJoined += self.unitMgr_onUnitJoined
            unitMgr.onUnitLeft += self.unitMgr_onUnitLeft
            unitMgr.onUnitRestored += self.unitMgr_onUnitRestored
            unitMgr.onUnitErrorReceived += self.unitMgr_onUnitErrorReceived
        else:
            LOG_ERROR('Unit manager is not defined')
        unitBrowser = prb_getters.getClientUnitBrowser()
        if unitBrowser:
            unitBrowser.onErrorReceived += self.unitBrowser_onErrorReceived
        else:
            LOG_ERROR('Unit browser is not defined')
        g_prbCtrlEvents.onLegacyIntroModeJoined += self.ctrl_onLegacyIntroModeJoined
        g_prbCtrlEvents.onLegacyIntroModeLeft += self.ctrl_onLegacyIntroModeLeft
        g_prbCtrlEvents.onLegacyInited += self.ctrl_onLegacyInited
        g_prbCtrlEvents.onUnitIntroModeJoined += self.ctrl_onUnitIntroModeJoined
        g_prbCtrlEvents.onUnitIntroModeLeft += self.ctrl_onUnitIntroModeLeft
        g_prbCtrlEvents.onUnitBrowserModeLeft += self.ctrl_onUnitBrowserModeLeft
        g_prbCtrlEvents.onPreQueueJoined += self.ctrl_onPreQueueJoined
        g_prbCtrlEvents.onPreQueueJoinFailure += self.ctrl_onPreQueueJoinFailure
        g_prbCtrlEvents.onPreQueueLeft += self.ctrl_onPreQueueLeft
        return

    def __stopListening(self):
        """
        Unsubscribe from player and system events.
        """
        g_playerEvents.onPrebattleJoined -= self.pe_onPrebattleJoined
        g_playerEvents.onPrebattleJoinFailure -= self.pe_onPrebattleJoinFailure
        g_playerEvents.onPrebattleLeft -= self.pe_onPrebattleLeft
        g_playerEvents.onKickedFromPrebattle -= self.pe_onKickedFromPrebattle
        g_playerEvents.onArenaCreated -= self.pe_onArenaCreated
        g_playerEvents.onArenaJoinFailure -= self.pe_onArenaJoinFailure
        g_playerEvents.onKickedFromArena -= self.pe_onKickedFromArena
        g_playerEvents.onPrebattleAutoInvitesChanged -= self.pe_onPrebattleAutoInvitesChanged
        g_playerEvents.onPrebattleInvitationsError -= self.pe_onPrebattleInviteError
        self.gameSession.onTimeTillBan -= self.gs_onTillBanNotification
        self.rentals.onRentChangeNotify -= self.rc_onRentChange
        self.igrCtrl.onIgrTypeChanged -= self.igr_onRoomChange
        unitMgr = prb_getters.getClientUnitMgr()
        if unitMgr:
            unitMgr.onUnitJoined -= self.unitMgr_onUnitJoined
            unitMgr.onUnitLeft -= self.unitMgr_onUnitLeft
            unitMgr.onUnitRestored -= self.unitMgr_onUnitRestored
            unitMgr.onUnitErrorReceived -= self.unitMgr_onUnitErrorReceived
        unitBrowser = prb_getters.getClientUnitBrowser()
        if unitBrowser:
            unitBrowser.onErrorReceived -= self.unitBrowser_onErrorReceived
        g_prbCtrlEvents.clear()

    def __clear(self, woEvents=False):
        """
        Clears dispatchers current state and attributes.
        Args:
            woEvents: flag that we should not raise any events
        """
        if self.__requestCtx:
            self.__requestCtx.clear()
            self.__requestCtx = None
        if self.__factories is not None:
            self.__factories.clear()
            self.__factories = None
        if self.__entity is not None:
            self.__entity.fini(woEvents=woEvents)
            self.__entity = None
        self.__prevEntity = None
        g_eventDispatcher.removeSpecBattlesFromCarousel()
        self.clear()
        return

    def __setLegacy(self, flags=FUNCTIONAL_FLAG.UNDEFINED, prbType=0):
        """
        Sets current entity to legacy and stops request processing.
        Args:
            flags: functional flags
            prbType: prebattle type
        
        Returns:
            initialization result as flags
        """
        return self.__setEntity(
            CreatePrbEntityCtx(_CTRL_TYPE.LEGACY,
                               prbType,
                               flags=flags,
                               initCtx=self.__requestCtx))

    def __setUnit(self, flags=FUNCTIONAL_FLAG.UNDEFINED, prbType=0):
        """
        Sets current entity to unit and stops request processing.
        Args:
            flags: functional flags
            prbType: prebattle type
        
        Returns:
            initialization result as flags
        """
        return self.__setEntity(
            CreatePrbEntityCtx(_CTRL_TYPE.UNIT,
                               prbType,
                               flags=flags,
                               initCtx=self.__requestCtx))

    def __setPreQueue(self, flags=FUNCTIONAL_FLAG.UNDEFINED, queueType=0):
        """
        Sets current entity to queue and stops request processing.
        Args:
            flags: functional flags
            queueType: queue type
        
        Returns:
            initialization result as flags
        """
        return self.__setEntity(
            CreatePrbEntityCtx(_CTRL_TYPE.PREQUEUE,
                               queueType,
                               flags=flags,
                               initCtx=self.__requestCtx))

    def __setDefault(self):
        """
        Sets current entity to default (allowing the system to initialize
        by itself) and stops request processing.
        Returns:
            initialization result as flags
        """
        return self.__setEntity(
            CreatePrbEntityCtx(flags=FUNCTIONAL_FLAG.DEFAULT))

    def __validateJoinOp(self, ctx):
        """
        Validates join operation: is request in process, is player already joined,
        or current entity has locked state.
        Args:
            ctx: join request context
        
        Returns:
            was validation passed
        """
        if self.__requestCtx.isProcessing():
            LOG_ERROR('Request is processing', self.__requestCtx)
            return False
        if self.__entity.isPlayerJoined(ctx):
            LOG_DEBUG('Player already joined', ctx)
            self.__entity.showGUI(ctx)
            return False
        if self.__entity.hasLockedState():
            SystemMessages.pushI18nMessage(
                '#system_messages:prebattle/hasLockedState',
                type=SystemMessages.SM_TYPE.Warning)
            return False
        return True

    def __unsetEntity(self, ctx=None):
        """
        Unset current entity.
        Args:
            ctx: leave, join or create request context
        """
        if not isinstance(self.__entity, NotSupportedEntity):
            self._invokeListeners('onPrbEntitySwitching')
            self.__entity.fini(ctx=ctx)
            self.__prevEntity = self.__entity
            self.__entity = NotSupportedEntity()
            self.__requestCtx.stopProcessing(result=True)

    def __setEntity(self, ctx):
        """
        Set current entity and clear request context.
        Args:
            ctx: set entity context
        
        Returns:
            integer containing initialization result as flags
        """
        created = self.__factories.createEntity(ctx)
        if created is not None:
            if created.getEntityFlags(
            ) & FUNCTIONAL_FLAG.SET_GLOBAL_LISTENERS > 0:
                created.addMutualListeners(self)
            self.__entity = created
            self.__prevEntity = NotSupportedEntity()
            flag = self.__entity.init(ctx=ctx)
            self._invokeListeners('onPrbEntitySwitched')
            ctx.clearFlags()
            ctx.addFlags(flag | created.getFunctionalFlags())
        LOG_DEBUG('Entity have been updated', ctx.getFlagsToStrings())
        ctx.clear()
        currentCtx = self.__requestCtx
        self.__requestCtx = PrbCtrlRequestCtx()
        currentCtx.stopProcessing(result=True)
        g_eventDispatcher.updateUI()
        return ctx.getFlags()
Пример #2
0
class _PreBattleDispatcher(ListenersCollection):
    gameSession = dependency.descriptor(IGameSessionController)
    rentals = dependency.descriptor(IRentalsController)
    igrCtrl = dependency.descriptor(IIGRController)
    eventsCache = dependency.descriptor(IEventsCache)

    def __init__(self):
        super(_PreBattleDispatcher, self).__init__()
        self.__requestCtx = PrbCtrlRequestCtx()
        self.__factories = ControlFactoryComposite()
        self.__entity = NotSupportedEntity()
        self.__prevEntity = NotSupportedEntity()
        self.__isStarted = False
        self._setListenerClass(IGlobalListener)

    def __del__(self):
        LOG_DEBUG('_PreBattleDispatcher deleted')

    def start(self):
        if self.__isStarted:
            return
        self.__isStarted = True
        g_eventDispatcher.init(self)
        result = self.__setDefault()
        self.__startListening()
        initDevFunctional()
        if result & FUNCTIONAL_FLAG.LOAD_PAGE == 0:
            g_eventDispatcher.loadHangar()
        if GUI_SETTINGS.specPrebatlesVisible and not prb_getters.areSpecBattlesHidden(
        ):
            g_eventDispatcher.addSpecBattlesToCarousel()

    def stop(self):
        if not self.__isStarted:
            return
        self.__isStarted = False
        self.__stopListening()
        finiDevFunctional()
        self.__clear(woEvents=True)
        g_eventDispatcher.fini()

    def getEntity(self):
        return self.__entity

    def getControlFactories(self):
        return self.__factories

    def getFunctionalState(self):
        factory = self.__factories.get(self.__entity.getCtrlType())
        return factory.createStateEntity(
            self.__entity) if factory is not None else FunctionalState()

    @async
    @process
    def create(self, ctx, callback=None):
        if ctx.getRequestType() != _RQ_TYPE.CREATE:
            LOG_ERROR('Invalid context to create prebattle/unit', ctx)
            if callback is not None:
                callback(False)
            return
        else:
            entry = self.__factories.createEntry(ctx)
            if entry is None:
                LOG_ERROR('Entry not found', ctx)
                if callback is not None:
                    callback(False)
                return
            if not entry.canCreate():
                if callback is not None:
                    callback(False)
                return
            ctx.addFlags(entry.getFunctionalFlags() | FUNCTIONAL_FLAG.SWITCH)
            if not self.__validateJoinOp(ctx):
                if callback is not None:
                    callback(False)
                return
            result = yield self.unlock(ctx)
            if not result:
                if callback is not None:
                    callback(False)
                return
            ctx.setForced(True)
            LOG_DEBUG('Request to create', ctx)
            self.__requestCtx = ctx
            entry.create(ctx, callback=callback)
            return

    @async
    @process
    def join(self, ctx, callback=None):
        if ctx.getRequestType() != _RQ_TYPE.JOIN:
            LOG_ERROR('Invalid context to join prebattle/unit', ctx)
            if callback is not None:
                callback(False)
            return
        else:
            entry = self.__factories.createEntry(ctx)
            if entry is None:
                LOG_ERROR('Entry not found', ctx)
                if callback is not None:
                    callback(False)
                return
            if not entry.canJoin():
                if callback is not None:
                    callback(False)
                return
            ctx.addFlags(entry.getFunctionalFlags() | FUNCTIONAL_FLAG.SWITCH)
            if not self.__validateJoinOp(ctx):
                if callback is not None:
                    callback(False)
                return
            result = yield self.unlock(ctx)
            if not result:
                if callback is not None:
                    callback(False)
                return
            ctx.setForced(True)
            LOG_DEBUG('Request to join', ctx)
            self.__requestCtx = ctx
            entry.join(ctx, callback=callback)
            return

    @async
    def leave(self, ctx, callback=None, ignoreConfirmation=False):
        if ctx.getRequestType() != _RQ_TYPE.LEAVE:
            LOG_ERROR('Invalid context to leave prebattle/unit', ctx)
            if callback is not None:
                callback(False)
            return
        elif self.__requestCtx.isProcessing():
            LOG_ERROR('Request is processing', self.__requestCtx)
            if callback is not None:
                callback(False)
            return
        else:
            entity = self.__entity
            if not ignoreConfirmation:
                meta = entity.getConfirmDialogMeta(ctx)
                if meta:
                    entity.showDialog(
                        meta, lambda result: self.__leaveCallback(
                            result, ctx, callback))
                    return
            self.__leaveLogic(ctx, callback)
            return

    def __leaveCallback(self, result, ctx, callback=None):
        if not result:
            if callback is not None:
                callback(False)
            return
        else:
            self.__leaveLogic(ctx, callback)
            return

    def __leaveLogic(self, ctx, callback):
        entity = self.__entity
        if not entity.isActive():
            if callback is not None:
                callback(False)
            return
        else:
            ctrlType = ctx.getCtrlType()
            if entity.hasLockedState():
                entityType = entity.getEntityType()
                SystemMessages.pushI18nMessage(
                    messages.getLeaveDisabledMessage(ctrlType, entityType),
                    type=SystemMessages.SM_TYPE.Warning)
                if callback is not None:
                    callback(False)
                return
            LOG_DEBUG('Request to leave formation', ctx)
            self.__requestCtx = ctx
            entity.leave(ctx, callback=callback)
            return

    @async
    @process
    def unlock(self, unlockCtx, callback=None):
        if isinstance(self.__entity, NotSupportedEntity):
            if callback is not None:
                callback(True)
            return
        else:
            state = self.getFunctionalState()
            ctrlType = state.ctrlTypeID
            factory = self.__factories.get(ctrlType)
            if factory is None:
                LOG_ERROR('Factory is not found', state)
                if callback is not None:
                    callback(True)
                return
            ctx = factory.createLeaveCtx(unlockCtx.getFlags(),
                                         self.__entity.getEntityType())
            result = yield self.leave(ctx)
            if callback is not None:
                callback(result)
            return

    @async
    @process
    def select(self, entry, callback=None):
        ctx = entry.makeDefCtx()
        ctx.addFlags(entry.getModeFlags() & FUNCTIONAL_FLAG.LOAD_PAGE
                     | FUNCTIONAL_FLAG.SWITCH)
        if not self.__validateJoinOp(ctx):
            if callback is not None:
                callback(False)
            return
        else:
            if entry.isVisualOnly():
                result = True
            else:
                result = yield self.unlock(ctx)
            if not result:
                if callback is not None:
                    callback(False)
                return
            ctx.setForced(True)
            LOG_DEBUG('Request to select', ctx)
            self.__requestCtx = ctx
            entry.select(ctx, callback=callback)
            return

    @async
    def sendPrbRequest(self, ctx, callback=None):
        self.__entity.request(ctx, callback=callback)

    def getPlayerInfo(self):
        factory = self.__factories.get(self.__entity.getCtrlType())
        return factory.createPlayerInfo(
            self.__entity) if factory is not None else PlayerDecorator()

    def doAction(self, action=None):
        if not g_currentVehicle.isPresent():
            SystemMessages.pushMessage(messages.getInvalidVehicleMessage(
                PREBATTLE_RESTRICTION.VEHICLE_NOT_PRESENT),
                                       type=SystemMessages.SM_TYPE.Error)
            return False
        LOG_DEBUG('Do GUI action', action)
        return self.__entity.doAction(action)

    @async
    @process
    def doSelectAction(self, action, callback=None):
        selectResult = self.__entity.doSelectAction(action)
        if selectResult.isProcessed:
            result = True
            if selectResult.newEntry is not None:
                result = yield self.select(selectResult.newEntry)
            if callback is not None:
                callback(result)
            return
        else:
            entry = self.__factories.createEntryByAction(action)
            if entry is not None:
                result = yield self.select(entry)
                if callback is not None:
                    callback(result)
                return
            if callback is not None:
                callback(False)
            return

    @async
    @process
    def doLeaveAction(self, action, callback=None):
        factory = self.__factories.get(self.__entity.getCtrlType())
        if factory is None:
            LOG_ERROR('Factory is not found', self.__entity)
            if callback is not None:
                callback(True)
            return
        else:
            flags = FUNCTIONAL_FLAG.UNDEFINED
            if action.isExit:
                flags = FUNCTIONAL_FLAG.EXIT
            elif self.__entity.canKeepMode():
                flags = self.__entity.getModeFlags()
            ctx = factory.createLeaveCtx(
                flags, entityType=self.__entity.getEntityType())
            if self.__entity.isInCoolDown(ctx.getRequestType()):
                if callback is not None:
                    callback(True)
                return
            self.__entity.setCoolDown(ctx.getRequestType(), ctx.getCooldown())
            result = yield self.leave(
                ctx, ignoreConfirmation=action.ignoreConfirmation)
            if callback is not None:
                callback(result)
            return

    def getGUIPermissions(self):
        return self.__entity.getPermissions()

    def isRequestInProcess(self):
        return self.__requestCtx.isProcessing()

    def restorePrevious(self):
        return self.__setEntity(
            CreatePrbEntityCtx(self.__prevEntity.getCtrlType(),
                               self.__prevEntity.getEntityType(),
                               flags=self.__prevEntity.getFunctionalFlags()))

    def pe_onArenaCreated(self):
        if self.__entity.hasLockedState():
            g_eventDispatcher.updateUI()

    def pe_onArenaJoinFailure(self, errorCode, errorStr):
        SystemMessages.pushMessage(messages.getJoinFailureMessage(errorCode),
                                   type=SystemMessages.SM_TYPE.Error)

    def pe_onKickedFromArena(self, reasonCode):
        self.__entity.resetPlayerState()
        SystemMessages.pushMessage(messages.getKickReasonMessage(reasonCode),
                                   type=SystemMessages.SM_TYPE.Error)

    def pe_onPrebattleAutoInvitesChanged(self):
        if GUI_SETTINGS.specPrebatlesVisible:
            isHidden = prb_getters.areSpecBattlesHidden()
            if isHidden:
                g_eventDispatcher.removeSpecBattlesFromCarousel()
            else:
                g_eventDispatcher.addSpecBattlesToCarousel()
        g_eventDispatcher.updateUI()

    def pe_onPrebattleInviteError(self, inviteID, errorCode, errorStr):
        self.__unsetEntity()
        self.__setDefault()

    def pe_onPrebattleJoined(self):
        if prb_getters.getClientPrebattle() is not None:
            self.__setLegacy(self.__requestCtx.getFlags())
        else:
            LOG_ERROR('ClientPrebattle is not defined')
            self.__setDefault()
            g_eventDispatcher.loadHangar()
        return

    def pe_onPrebattleJoinFailure(self, errorCode):
        SystemMessages.pushMessage(messages.getJoinFailureMessage(errorCode),
                                   type=SystemMessages.SM_TYPE.Error)
        self.__setDefault()
        g_eventDispatcher.loadHangar()

    def pe_onPrebattleLeft(self):
        flags = self.__requestCtx.getFlags()
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            prbType = 0
            if flags & FUNCTIONAL_FLAG.EXIT == 0:
                prbType = self.__entity.getEntityType()
            self.__unsetEntity(self.__requestCtx)
            self.__setLegacy(flags=flags, prbType=prbType)
        else:
            self.__unsetEntity(self.__requestCtx)

    def pe_onKickedFromPrebattle(self, kickReason):
        self.__unsetEntity()
        self.__setDefault()

    def ctrl_onLegacyIntroModeJoined(self, prbType):
        self.__setLegacy(flags=self.__requestCtx.getFlags(), prbType=prbType)

    def ctrl_onLegacyIntroModeLeft(self):
        flags = self.__requestCtx.getFlags()
        self.__unsetEntity(self.__requestCtx)
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            self.__setDefault()

    def ctrl_onLegacyInited(self):
        self.__setLegacy(flags=self.__requestCtx.getFlags())

    def ctrl_onUnitIntroModeJoined(self, prbType, flags):
        self.__setUnit(flags=flags, prbType=prbType)

    def ctrl_onUnitBrowserModeLeft(self, prbType):
        flags = self.__requestCtx.getFlags()
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            prbType = 0
            if flags & FUNCTIONAL_FLAG.EXIT == 0:
                unitEntity = self.__entity
                if unitEntity.canKeepMode():
                    prbType = unitEntity.getIntroType()
                    flags |= unitEntity.getModeFlags()
            self.__unsetEntity(self.__requestCtx)
            self.__setUnit(flags=flags, prbType=prbType)
        else:
            self.__unsetEntity(self.__requestCtx)

    def ctrl_onUnitIntroModeLeft(self):
        flags = self.__requestCtx.getFlags()
        self.__unsetEntity(self.__requestCtx)
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            self.__setDefault()

    def unitMgr_onUnitJoined(self, unitMgrID, prbType):
        entity = self.__entity
        ctx = JoinUnitCtx(unitMgrID, prbType)
        if entity.isPlayerJoined(ctx):
            entity.rejoin()
        else:
            self.__setUnit(flags=self.__requestCtx.getFlags(),
                           prbType=self.__requestCtx.getEntityType())

    def unitMgr_onUnitLeft(self, unitMgrID, isFinishedAssembling):
        flags = self.__requestCtx.getFlags()
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            prbType = 0
            if flags & FUNCTIONAL_FLAG.EXIT == 0:
                unitEntity = self.__entity
                if unitEntity.canKeepMode():
                    prbType = unitEntity.getEntityType()
                    flags |= unitEntity.getModeFlags(
                    ) | FUNCTIONAL_FLAG.UNIT_BROWSER
            self.__unsetEntity(self.__requestCtx)
            self.__setUnit(flags=flags, prbType=prbType)
        else:
            self.__unsetEntity(self.__requestCtx)

    def unitMgr_onUnitRestored(self, unitMgrID):
        self.__entity.restore()

    def unitMgr_onUnitErrorReceived(self, requestID, unitMgrID, errorCode,
                                    errorString):
        if errorCode not in IGNORED_UNIT_MGR_ERRORS:
            msgType, msgBody = messages.getUnitMessage(errorCode, errorString)
            SystemMessages.pushMessage(msgBody, type=msgType)
            self.__requestCtx.stopProcessing()
        if errorCode in ENTER_UNIT_MGR_ERRORS:
            self.restorePrevious()

    def unitMgr_onUnitNotifyReceived(self, unitMgrID, notifyCode, notifyString,
                                     argsList):
        if notifyCode in UNIT_NOTIFICATION_TO_DISPLAY:
            msgType, msgBody = messages.getUnitMessage(notifyCode,
                                                       notifyString)
            SystemMessages.pushMessage(msgBody, type=msgType)
            self.__requestCtx.stopProcessing()

    def unitBrowser_onErrorReceived(self, errorCode, errorString):
        if errorCode not in IGNORED_UNIT_BROWSER_ERRORS:
            msgType, msgBody = messages.getUnitBrowserMessage(
                errorCode, errorString)
            SystemMessages.pushMessage(msgBody, type=msgType)
            self.__unsetEntity()
            self.__setDefault()

    def ctrl_onPreQueueJoined(self, queueType):
        self.__setPreQueue(flags=self.__requestCtx.getFlags(),
                           queueType=queueType)

    def ctrl_onPreQueueJoinFailure(self, errorCode):
        self.__setDefault()

    def ctrl_onPreQueueLeft(self):
        flags = self.__requestCtx.getFlags()
        self.__unsetEntity(self.__requestCtx)
        if flags & FUNCTIONAL_FLAG.SWITCH == 0:
            self.__setDefault()

    def gs_onTillBanNotification(self, isPlayTimeBan, timeTillBlock):
        if prb_getters.isParentControlActivated():
            self.__entity.resetPlayerState()
            key = '#system_messages:gameSessionControl/korea/{0:>s}'
            if isPlayTimeBan:
                SystemMessages.pushI18nMessage(
                    key.format('playTimeNotification'),
                    timeTillBlock,
                    type=SystemMessages.SM_TYPE.Warning)
            else:
                _, blockTime = self.gameSession.getCurfewBlockTime()
                formatter = lambda t: time.strftime('%H:%M', time.localtime(t))
                SystemMessages.pushI18nMessage(
                    key.format('midnightNotification'),
                    type=SystemMessages.SM_TYPE.Warning,
                    blockTime=formatter(blockTime))

    def rc_onRentChange(self, vehicles):
        if g_currentVehicle.isPresent(
        ) and g_currentVehicle.item.intCD in vehicles and g_currentVehicle.isDisabledInRent(
        ) and g_currentVehicle.isInPrebattle():
            self.__entity.resetPlayerState()

    def igr_onRoomChange(self, roomType, xpFactor):
        if roomType != IGR_TYPE.PREMIUM:
            if g_currentVehicle.isPremiumIGR(
            ) and g_currentVehicle.isInPrebattle():
                self.__entity.resetPlayerState()

    def notifyPrbEntitySwitched(self):
        if self.__isStarted:
            self._invokeListeners('onPrbEntitySwitched')

    def __startListening(self):
        g_playerEvents.onPrebattleJoined += self.pe_onPrebattleJoined
        g_playerEvents.onPrebattleJoinFailure += self.pe_onPrebattleJoinFailure
        g_playerEvents.onPrebattleLeft += self.pe_onPrebattleLeft
        g_playerEvents.onKickedFromPrebattle += self.pe_onKickedFromPrebattle
        g_playerEvents.onArenaCreated += self.pe_onArenaCreated
        g_playerEvents.onArenaJoinFailure += self.pe_onArenaJoinFailure
        g_playerEvents.onKickedFromArena += self.pe_onKickedFromArena
        g_playerEvents.onPrebattleAutoInvitesChanged += self.pe_onPrebattleAutoInvitesChanged
        g_playerEvents.onPrebattleInvitationsError += self.pe_onPrebattleInviteError
        g_playerEvents.onUpdateSpecBattlesWindow += self.pe_onPrebattleAutoInvitesChanged
        if self.gameSession.lastBanMsg is not None:
            self.gs_onTillBanNotification(*self.gameSession.lastBanMsg)
        self.gameSession.onTimeTillBan += self.gs_onTillBanNotification
        self.rentals.onRentChangeNotify += self.rc_onRentChange
        self.igrCtrl.onIgrTypeChanged += self.igr_onRoomChange
        unitMgr = prb_getters.getClientUnitMgr()
        if unitMgr:
            unitMgr.onUnitJoined += self.unitMgr_onUnitJoined
            unitMgr.onUnitLeft += self.unitMgr_onUnitLeft
            unitMgr.onUnitRestored += self.unitMgr_onUnitRestored
            unitMgr.onUnitErrorReceived += self.unitMgr_onUnitErrorReceived
            unitMgr.onUnitNotifyReceived += self.unitMgr_onUnitNotifyReceived
        else:
            LOG_ERROR('Unit manager is not defined')
        unitBrowser = prb_getters.getClientUnitBrowser()
        if unitBrowser:
            unitBrowser.onErrorReceived += self.unitBrowser_onErrorReceived
        else:
            LOG_ERROR('Unit browser is not defined')
        g_prbCtrlEvents.onLegacyIntroModeJoined += self.ctrl_onLegacyIntroModeJoined
        g_prbCtrlEvents.onLegacyIntroModeLeft += self.ctrl_onLegacyIntroModeLeft
        g_prbCtrlEvents.onLegacyInited += self.ctrl_onLegacyInited
        g_prbCtrlEvents.onUnitIntroModeJoined += self.ctrl_onUnitIntroModeJoined
        g_prbCtrlEvents.onUnitIntroModeLeft += self.ctrl_onUnitIntroModeLeft
        g_prbCtrlEvents.onUnitBrowserModeLeft += self.ctrl_onUnitBrowserModeLeft
        g_prbCtrlEvents.onPreQueueJoined += self.ctrl_onPreQueueJoined
        g_prbCtrlEvents.onPreQueueJoinFailure += self.ctrl_onPreQueueJoinFailure
        g_prbCtrlEvents.onPreQueueLeft += self.ctrl_onPreQueueLeft
        g_eventBus.addListener(events.PrbActionEvent.SELECT,
                               self.__onDoSelectAction,
                               scope=EVENT_BUS_SCOPE.LOBBY)
        g_eventBus.addListener(events.PrbActionEvent.LEAVE,
                               self.__onDoLeaveAction,
                               scope=EVENT_BUS_SCOPE.LOBBY)
        return

    def __stopListening(self):
        g_playerEvents.onPrebattleJoined -= self.pe_onPrebattleJoined
        g_playerEvents.onPrebattleJoinFailure -= self.pe_onPrebattleJoinFailure
        g_playerEvents.onPrebattleLeft -= self.pe_onPrebattleLeft
        g_playerEvents.onKickedFromPrebattle -= self.pe_onKickedFromPrebattle
        g_playerEvents.onArenaCreated -= self.pe_onArenaCreated
        g_playerEvents.onArenaJoinFailure -= self.pe_onArenaJoinFailure
        g_playerEvents.onKickedFromArena -= self.pe_onKickedFromArena
        g_playerEvents.onPrebattleAutoInvitesChanged -= self.pe_onPrebattleAutoInvitesChanged
        g_playerEvents.onPrebattleInvitationsError -= self.pe_onPrebattleInviteError
        g_playerEvents.onUpdateSpecBattlesWindow -= self.pe_onPrebattleAutoInvitesChanged
        self.gameSession.onTimeTillBan -= self.gs_onTillBanNotification
        self.rentals.onRentChangeNotify -= self.rc_onRentChange
        self.igrCtrl.onIgrTypeChanged -= self.igr_onRoomChange
        unitMgr = prb_getters.getClientUnitMgr()
        if unitMgr:
            unitMgr.onUnitJoined -= self.unitMgr_onUnitJoined
            unitMgr.onUnitLeft -= self.unitMgr_onUnitLeft
            unitMgr.onUnitRestored -= self.unitMgr_onUnitRestored
            unitMgr.onUnitErrorReceived -= self.unitMgr_onUnitErrorReceived
            unitMgr.onUnitNotifyReceived -= self.unitMgr_onUnitNotifyReceived
        unitBrowser = prb_getters.getClientUnitBrowser()
        if unitBrowser:
            unitBrowser.onErrorReceived -= self.unitBrowser_onErrorReceived
        g_prbCtrlEvents.clear()
        g_eventBus.removeListener(events.PrbActionEvent.SELECT,
                                  self.__onDoSelectAction,
                                  scope=EVENT_BUS_SCOPE.LOBBY)
        g_eventBus.removeListener(events.PrbActionEvent.LEAVE,
                                  self.__onDoLeaveAction,
                                  scope=EVENT_BUS_SCOPE.LOBBY)

    def __clear(self, woEvents=False):
        if self.__requestCtx:
            self.__requestCtx.clear()
            self.__requestCtx = None
        if self.__factories is not None:
            self.__factories.clear()
            self.__factories = None
        if self.__entity is not None:
            self.__entity.fini(woEvents=woEvents)
            self.__entity = None
        self.__prevEntity = None
        g_eventDispatcher.removeSpecBattlesFromCarousel()
        self.clear()
        return

    def __setLegacy(self, flags=FUNCTIONAL_FLAG.UNDEFINED, prbType=0):
        return self.__setEntity(
            CreatePrbEntityCtx(_CTRL_TYPE.LEGACY,
                               prbType,
                               flags=flags,
                               initCtx=self.__requestCtx))

    def __setUnit(self, flags=FUNCTIONAL_FLAG.UNDEFINED, prbType=0):
        return self.__setEntity(
            CreatePrbEntityCtx(_CTRL_TYPE.UNIT,
                               prbType,
                               flags=flags,
                               initCtx=self.__requestCtx))

    def __setPreQueue(self, flags=FUNCTIONAL_FLAG.UNDEFINED, queueType=0):
        return self.__setEntity(
            CreatePrbEntityCtx(_CTRL_TYPE.PREQUEUE,
                               queueType,
                               flags=flags,
                               initCtx=self.__requestCtx))

    def __setDefault(self):
        return self.__setEntity(
            CreatePrbEntityCtx(flags=FUNCTIONAL_FLAG.DEFAULT))

    def __validateJoinOp(self, ctx):
        if self.__requestCtx.isProcessing():
            LOG_ERROR('Request is processing', self.__requestCtx)
            return False
        if self.__entity.isPlayerJoined(ctx):
            LOG_DEBUG('Player already joined', ctx)
            self.__entity.showGUI(ctx)
            return False
        if self.__entity.hasLockedState():
            SystemMessages.pushI18nMessage(
                '#system_messages:prebattle/hasLockedState',
                type=SystemMessages.SM_TYPE.Warning)
            return False
        return True

    def __unsetEntity(self, ctx=None):
        if not isinstance(self.__entity, NotSupportedEntity):
            self._invokeListeners('onPrbEntitySwitching')
            self.__entity.fini(ctx=ctx)
            self.__prevEntity = self.__entity
            self.__entity = NotSupportedEntity()
            self.__requestCtx.stopProcessing(result=True)

    def __setEntity(self, ctx):
        created = self.__factories.createEntity(ctx)
        if created is not None:
            if created.getEntityFlags(
            ) & FUNCTIONAL_FLAG.SET_GLOBAL_LISTENERS > 0:
                created.addMutualListeners(self)
            if self.__entity is not None and not isinstance(
                    self.__entity, NotSupportedEntity):
                _logger.info(
                    "__setEntity() new entity '%r' was created, previous entity '%r' was stopped",
                    created, self.__entity)
                self.__entity.fini()
            self.__entity = created
            if self.__prevEntity is not None and self.__prevEntity.isActive():
                self.__prevEntity.fini()
            self.__prevEntity = NotSupportedEntity()
            flag = self.__entity.init(ctx=ctx)
            self.notifyPrbEntitySwitched()
            ctx.clearFlags()
            ctx.addFlags(flag | created.getFunctionalFlags())
        LOG_DEBUG('Entity have been updated', ctx.getFlagsToStrings())
        ctx.clear()
        currentCtx = self.__requestCtx
        self.__requestCtx = PrbCtrlRequestCtx()
        currentCtx.stopProcessing(result=True)
        g_eventDispatcher.updateUI()
        return ctx.getFlags()

    @process
    def __onDoSelectAction(self, event):
        yield self.doSelectAction(event.action)

    @process
    def __onDoLeaveAction(self, event):
        yield self.doLeaveAction(event.action)